mirror of
https://github.com/NVIDIA/nvidia-container-toolkit
synced 2024-11-22 00:08:11 +00:00
Add creation of select driver symlinks to CDI spec
This change aligns the creation of symlinks under CDI with the implementation in libnvidia-container. If the driver libraries are present, the following symlinks are created: * {{ .LibRoot }}/libcuda.so -> libcuda.so.1 * {{ .LibRoot }}/libnvidia-opticalflow.so -> libnvidia-opticalflow.so.1 * {{ .LibRoot }}/libGLX_indirect.so.0 -> libGLX_nvidia.so.{{ .Version }} Signed-off-by: Evan Lezar <elezar@nvidia.com>
This commit is contained in:
parent
a5a5833c14
commit
838910d29b
@ -24,15 +24,15 @@ var _ Discover = (*None)(nil)
|
|||||||
|
|
||||||
// Devices returns an empty list of devices
|
// Devices returns an empty list of devices
|
||||||
func (e None) Devices() ([]Device, error) {
|
func (e None) Devices() ([]Device, error) {
|
||||||
return []Device{}, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mounts returns an empty list of mounts
|
// Mounts returns an empty list of mounts
|
||||||
func (e None) Mounts() ([]Mount, error) {
|
func (e None) Mounts() ([]Mount, error) {
|
||||||
return []Mount{}, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hooks returns an empty list of hooks
|
// Hooks returns an empty list of hooks
|
||||||
func (e None) Hooks() ([]Hook, error) {
|
func (e None) Hooks() ([]Hook, error) {
|
||||||
return []Hook{}, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
108
internal/discover/symlinks.go
Normal file
108
internal/discover/symlinks.go
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
/**
|
||||||
|
# Copyright 2024 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 discover
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"path/filepath"
|
||||||
|
)
|
||||||
|
|
||||||
|
type additionalSymlinks struct {
|
||||||
|
Discover
|
||||||
|
version string
|
||||||
|
nvidiaCDIHookPath string
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithDriverDotSoSymlinks decorates the provided discoverer.
|
||||||
|
// A hook is added that checks for specific driver symlinks that need to be created.
|
||||||
|
func WithDriverDotSoSymlinks(mounts Discover, version string, nvidiaCDIHookPath string) Discover {
|
||||||
|
if version == "" {
|
||||||
|
version = "*.*"
|
||||||
|
}
|
||||||
|
return &additionalSymlinks{
|
||||||
|
Discover: mounts,
|
||||||
|
nvidiaCDIHookPath: nvidiaCDIHookPath,
|
||||||
|
version: version,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hooks returns a hook to create the additional symlinks based on the mounts.
|
||||||
|
func (d *additionalSymlinks) Hooks() ([]Hook, error) {
|
||||||
|
mounts, err := d.Discover.Mounts()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get library mounts: %v", err)
|
||||||
|
}
|
||||||
|
hooks, err := d.Discover.Hooks()
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get hooks: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var links []string
|
||||||
|
processedPaths := make(map[string]bool)
|
||||||
|
processedLinks := make(map[string]bool)
|
||||||
|
for _, mount := range mounts {
|
||||||
|
if processedPaths[mount.Path] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
processedPaths[mount.Path] = true
|
||||||
|
|
||||||
|
for _, link := range d.getLinksForMount(mount.Path) {
|
||||||
|
if processedLinks[link] {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
processedLinks[link] = true
|
||||||
|
links = append(links, link)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(links) == 0 {
|
||||||
|
return hooks, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
hook := CreateCreateSymlinkHook(d.nvidiaCDIHookPath, links).(Hook)
|
||||||
|
return append(hooks, hook), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// getLinksForMount maps the path to created links if any.
|
||||||
|
func (d additionalSymlinks) getLinksForMount(path string) []string {
|
||||||
|
dir, filename := filepath.Split(path)
|
||||||
|
switch {
|
||||||
|
case d.isDriverLibrary("libcuda.so", filename):
|
||||||
|
// XXX Many applications wrongly assume that libcuda.so exists (e.g. with dlopen).
|
||||||
|
// create libcuda.so -> libcuda.so.1 symlink
|
||||||
|
link := fmt.Sprintf("%s::%s", "libcuda.so.1", filepath.Join(dir, "libcuda.so"))
|
||||||
|
return []string{link}
|
||||||
|
case d.isDriverLibrary("libGLX_nvidia.so", filename):
|
||||||
|
// XXX GLVND requires this symlink for indirect GLX support.
|
||||||
|
// create libGLX_indirect.so.0 -> libGLX_nvidia.so.VERSION symlink
|
||||||
|
link := fmt.Sprintf("%s::%s", filename, filepath.Join(dir, "libGLX_indirect.so.0"))
|
||||||
|
return []string{link}
|
||||||
|
case d.isDriverLibrary("libnvidia-opticalflow.so", filename):
|
||||||
|
// XXX Fix missing symlink for libnvidia-opticalflow.so.
|
||||||
|
// create libnvidia-opticalflow.so -> libnvidia-opticalflow.so.1 symlink
|
||||||
|
link := fmt.Sprintf("%s::%s", "libnvidia-opticalflow.so.1", filepath.Join(dir, "libnvidia-opticalflow.so"))
|
||||||
|
return []string{link}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// isDriverLibrary checks whether the specified filename is a specific driver library.
|
||||||
|
func (d additionalSymlinks) isDriverLibrary(libraryName string, filename string) bool {
|
||||||
|
pattern := libraryName + "." + d.version
|
||||||
|
match, _ := filepath.Match(pattern, filename)
|
||||||
|
return match
|
||||||
|
}
|
330
internal/discover/symlinks_test.go
Normal file
330
internal/discover/symlinks_test.go
Normal file
@ -0,0 +1,330 @@
|
|||||||
|
/**
|
||||||
|
# Copyright 2024 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 discover
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestWithWithDriverDotSoSymlinks(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
description string
|
||||||
|
discover Discover
|
||||||
|
version string
|
||||||
|
expectedDevices []Device
|
||||||
|
expectedDevicesError error
|
||||||
|
expectedHooks []Hook
|
||||||
|
expectedHooksError error
|
||||||
|
expectedMounts []Mount
|
||||||
|
expectedMountsError error
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
description: "empty discoverer remains empty",
|
||||||
|
discover: None{},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "non-matching discoverer remains unchanged",
|
||||||
|
discover: &DiscoverMock{
|
||||||
|
DevicesFunc: func() ([]Device, error) {
|
||||||
|
devices := []Device{
|
||||||
|
{
|
||||||
|
Path: "/dev/dev1",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return devices, nil
|
||||||
|
},
|
||||||
|
HooksFunc: func() ([]Hook, error) {
|
||||||
|
hooks := []Hook{
|
||||||
|
{
|
||||||
|
Lifecycle: "prestart",
|
||||||
|
Path: "/path/to/a/hook",
|
||||||
|
Args: []string{"hook", "arg1", "arg2"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return hooks, nil
|
||||||
|
},
|
||||||
|
MountsFunc: func() ([]Mount, error) {
|
||||||
|
mounts := []Mount{
|
||||||
|
{
|
||||||
|
Path: "/usr/lib/libnotcuda.so.1.2.3",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return mounts, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedDevices: []Device{
|
||||||
|
{
|
||||||
|
Path: "/dev/dev1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedHooks: []Hook{
|
||||||
|
{
|
||||||
|
Lifecycle: "prestart",
|
||||||
|
Path: "/path/to/a/hook",
|
||||||
|
Args: []string{"hook", "arg1", "arg2"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedMounts: []Mount{
|
||||||
|
{
|
||||||
|
Path: "/usr/lib/libnotcuda.so.1.2.3",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "libcuda.so.RM_VERSION is matched",
|
||||||
|
discover: &DiscoverMock{
|
||||||
|
DevicesFunc: func() ([]Device, error) {
|
||||||
|
return nil, nil
|
||||||
|
},
|
||||||
|
HooksFunc: func() ([]Hook, error) {
|
||||||
|
return nil, nil
|
||||||
|
},
|
||||||
|
MountsFunc: func() ([]Mount, error) {
|
||||||
|
mounts := []Mount{
|
||||||
|
{
|
||||||
|
Path: "/usr/lib/libcuda.so.1.2.3",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return mounts, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
version: "1.2.3",
|
||||||
|
expectedMounts: []Mount{
|
||||||
|
{
|
||||||
|
Path: "/usr/lib/libcuda.so.1.2.3",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedHooks: []Hook{
|
||||||
|
{
|
||||||
|
Lifecycle: "createContainer",
|
||||||
|
Path: "/path/to/nvidia-cdi-hook",
|
||||||
|
Args: []string{"nvidia-cdi-hook", "create-symlinks", "--link", "libcuda.so.1::/usr/lib/libcuda.so"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "libcuda.so.RM_VERSION is matched by pattern",
|
||||||
|
discover: &DiscoverMock{
|
||||||
|
DevicesFunc: func() ([]Device, error) {
|
||||||
|
return nil, nil
|
||||||
|
},
|
||||||
|
HooksFunc: func() ([]Hook, error) {
|
||||||
|
return nil, nil
|
||||||
|
},
|
||||||
|
MountsFunc: func() ([]Mount, error) {
|
||||||
|
mounts := []Mount{
|
||||||
|
{
|
||||||
|
Path: "/usr/lib/libcuda.so.1.2.3",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return mounts, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
version: "",
|
||||||
|
expectedMounts: []Mount{
|
||||||
|
{
|
||||||
|
Path: "/usr/lib/libcuda.so.1.2.3",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedHooks: []Hook{
|
||||||
|
{
|
||||||
|
Lifecycle: "createContainer",
|
||||||
|
Path: "/path/to/nvidia-cdi-hook",
|
||||||
|
Args: []string{"nvidia-cdi-hook", "create-symlinks", "--link", "libcuda.so.1::/usr/lib/libcuda.so"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "beta libcuda.so.RM_VERSION is matched",
|
||||||
|
discover: &DiscoverMock{
|
||||||
|
DevicesFunc: func() ([]Device, error) {
|
||||||
|
return nil, nil
|
||||||
|
},
|
||||||
|
HooksFunc: func() ([]Hook, error) {
|
||||||
|
return nil, nil
|
||||||
|
},
|
||||||
|
MountsFunc: func() ([]Mount, error) {
|
||||||
|
mounts := []Mount{
|
||||||
|
{
|
||||||
|
Path: "/usr/lib/libcuda.so.1.2",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return mounts, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedMounts: []Mount{
|
||||||
|
{
|
||||||
|
Path: "/usr/lib/libcuda.so.1.2",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedHooks: []Hook{
|
||||||
|
{
|
||||||
|
Lifecycle: "createContainer",
|
||||||
|
Path: "/path/to/nvidia-cdi-hook",
|
||||||
|
Args: []string{"nvidia-cdi-hook", "create-symlinks", "--link", "libcuda.so.1::/usr/lib/libcuda.so"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "non-matching libcuda.so.RM_VERSION is ignored",
|
||||||
|
discover: &DiscoverMock{
|
||||||
|
DevicesFunc: func() ([]Device, error) {
|
||||||
|
return nil, nil
|
||||||
|
},
|
||||||
|
HooksFunc: func() ([]Hook, error) {
|
||||||
|
return nil, nil
|
||||||
|
},
|
||||||
|
MountsFunc: func() ([]Mount, error) {
|
||||||
|
mounts := []Mount{
|
||||||
|
{
|
||||||
|
Path: "/usr/lib/libcuda.so.1.2.3",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return mounts, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
version: "4.5.6",
|
||||||
|
expectedMounts: []Mount{
|
||||||
|
{
|
||||||
|
Path: "/usr/lib/libcuda.so.1.2.3",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "hooks are extended",
|
||||||
|
discover: &DiscoverMock{
|
||||||
|
DevicesFunc: func() ([]Device, error) {
|
||||||
|
return nil, nil
|
||||||
|
},
|
||||||
|
HooksFunc: func() ([]Hook, error) {
|
||||||
|
hooks := []Hook{
|
||||||
|
{
|
||||||
|
Lifecycle: "prestart",
|
||||||
|
Path: "/path/to/a/hook",
|
||||||
|
Args: []string{"hook", "arg1", "arg2"},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return hooks, nil
|
||||||
|
},
|
||||||
|
MountsFunc: func() ([]Mount, error) {
|
||||||
|
mounts := []Mount{
|
||||||
|
{
|
||||||
|
Path: "/usr/lib/libcuda.so.1.2.3",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return mounts, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
version: "1.2.3",
|
||||||
|
expectedMounts: []Mount{
|
||||||
|
{
|
||||||
|
Path: "/usr/lib/libcuda.so.1.2.3",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedHooks: []Hook{
|
||||||
|
{
|
||||||
|
Lifecycle: "prestart",
|
||||||
|
Path: "/path/to/a/hook",
|
||||||
|
Args: []string{"hook", "arg1", "arg2"},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Lifecycle: "createContainer",
|
||||||
|
Path: "/path/to/nvidia-cdi-hook",
|
||||||
|
Args: []string{"nvidia-cdi-hook", "create-symlinks", "--link", "libcuda.so.1::/usr/lib/libcuda.so"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "all driver so symlinks are matched",
|
||||||
|
discover: &DiscoverMock{
|
||||||
|
DevicesFunc: func() ([]Device, error) {
|
||||||
|
return nil, nil
|
||||||
|
},
|
||||||
|
HooksFunc: func() ([]Hook, error) {
|
||||||
|
return nil, nil
|
||||||
|
},
|
||||||
|
MountsFunc: func() ([]Mount, error) {
|
||||||
|
mounts := []Mount{
|
||||||
|
{
|
||||||
|
Path: "/usr/lib/libcuda.so.1.2.3",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Path: "/usr/lib/libGLX_nvidia.so.1.2.3",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Path: "/usr/lib/libnvidia-opticalflow.so.1.2.3",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Path: "/usr/lib/libanother.so.1.2.3",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
return mounts, nil
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedMounts: []Mount{
|
||||||
|
{
|
||||||
|
Path: "/usr/lib/libcuda.so.1.2.3",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Path: "/usr/lib/libGLX_nvidia.so.1.2.3",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Path: "/usr/lib/libnvidia-opticalflow.so.1.2.3",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Path: "/usr/lib/libanother.so.1.2.3",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedHooks: []Hook{
|
||||||
|
{
|
||||||
|
Lifecycle: "createContainer",
|
||||||
|
Path: "/path/to/nvidia-cdi-hook",
|
||||||
|
Args: []string{
|
||||||
|
"nvidia-cdi-hook", "create-symlinks",
|
||||||
|
"--link", "libcuda.so.1::/usr/lib/libcuda.so",
|
||||||
|
"--link", "libGLX_nvidia.so.1.2.3::/usr/lib/libGLX_indirect.so.0",
|
||||||
|
"--link", "libnvidia-opticalflow.so.1::/usr/lib/libnvidia-opticalflow.so",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
t.Run(tc.description, func(t *testing.T) {
|
||||||
|
d := WithDriverDotSoSymlinks(
|
||||||
|
tc.discover,
|
||||||
|
tc.version,
|
||||||
|
"/path/to/nvidia-cdi-hook",
|
||||||
|
)
|
||||||
|
|
||||||
|
devices, err := d.Devices()
|
||||||
|
require.ErrorIs(t, err, tc.expectedDevicesError)
|
||||||
|
require.EqualValues(t, tc.expectedDevices, devices)
|
||||||
|
|
||||||
|
hooks, err := d.Hooks()
|
||||||
|
require.ErrorIs(t, err, tc.expectedHooksError)
|
||||||
|
require.EqualValues(t, tc.expectedHooks, hooks)
|
||||||
|
|
||||||
|
mounts, err := d.Mounts()
|
||||||
|
require.ErrorIs(t, err, tc.expectedMountsError)
|
||||||
|
require.EqualValues(t, tc.expectedMounts, mounts)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -139,7 +139,7 @@ func TestNewNvmlMIGDiscoverer(t *testing.T) {
|
|||||||
},
|
},
|
||||||
expectedDevices: nil,
|
expectedDevices: nil,
|
||||||
expectedMounts: nil,
|
expectedMounts: nil,
|
||||||
expectedHooks: []discover.Hook{},
|
expectedHooks: nil,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
for _, tc := range testCases {
|
for _, tc := range testCases {
|
||||||
|
@ -49,14 +49,20 @@ func (o tegraOptions) newDiscovererFromCSVFiles() (discover.Discover, error) {
|
|||||||
targetsByType[csv.MountSpecDir],
|
targetsByType[csv.MountSpecDir],
|
||||||
)
|
)
|
||||||
|
|
||||||
// Libraries and symlinks use the same locator.
|
// We create a discoverer for mounted libraries and add additional .so
|
||||||
libraries := discover.NewMounts(
|
// symlinks for the driver.
|
||||||
o.logger,
|
libraries := discover.WithDriverDotSoSymlinks(
|
||||||
o.symlinkLocator,
|
discover.NewMounts(
|
||||||
o.driverRoot,
|
o.logger,
|
||||||
targetsByType[csv.MountSpecLib],
|
o.symlinkLocator,
|
||||||
|
o.driverRoot,
|
||||||
|
targetsByType[csv.MountSpecLib],
|
||||||
|
),
|
||||||
|
"",
|
||||||
|
o.nvidiaCDIHookPath,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// We process the expliclitlty requested symlinks.
|
||||||
symlinkTargets := o.ignorePatterns.Apply(targetsByType[csv.MountSpecSym]...)
|
symlinkTargets := o.ignorePatterns.Apply(targetsByType[csv.MountSpecSym]...)
|
||||||
o.logger.Debugf("Filtered symlink targets: %v", symlinkTargets)
|
o.logger.Debugf("Filtered symlink targets: %v", symlinkTargets)
|
||||||
symlinks := discover.NewMounts(
|
symlinks := discover.NewMounts(
|
||||||
@ -65,7 +71,7 @@ func (o tegraOptions) newDiscovererFromCSVFiles() (discover.Discover, error) {
|
|||||||
o.driverRoot,
|
o.driverRoot,
|
||||||
symlinkTargets,
|
symlinkTargets,
|
||||||
)
|
)
|
||||||
createSymlinks := o.createCSVSymlinkHooks(symlinkTargets, libraries)
|
createSymlinks := o.createCSVSymlinkHooks(symlinkTargets)
|
||||||
|
|
||||||
d := discover.Merge(
|
d := discover.Merge(
|
||||||
devices,
|
devices,
|
||||||
|
@ -18,8 +18,6 @@ package tegra
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"path/filepath"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/discover"
|
"github.com/NVIDIA/nvidia-container-toolkit/internal/discover"
|
||||||
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
|
||||||
@ -31,7 +29,6 @@ type symlinkHook struct {
|
|||||||
logger logger.Interface
|
logger logger.Interface
|
||||||
nvidiaCDIHookPath string
|
nvidiaCDIHookPath string
|
||||||
targets []string
|
targets []string
|
||||||
mountsFrom discover.Discover
|
|
||||||
|
|
||||||
// The following can be overridden for testing
|
// The following can be overridden for testing
|
||||||
symlinkChainLocator lookup.Locator
|
symlinkChainLocator lookup.Locator
|
||||||
@ -39,12 +36,11 @@ type symlinkHook struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// createCSVSymlinkHooks creates a discoverer for a hook that creates required symlinks in the container
|
// createCSVSymlinkHooks creates a discoverer for a hook that creates required symlinks in the container
|
||||||
func (o tegraOptions) createCSVSymlinkHooks(targets []string, mounts discover.Discover) discover.Discover {
|
func (o tegraOptions) createCSVSymlinkHooks(targets []string) discover.Discover {
|
||||||
return symlinkHook{
|
return symlinkHook{
|
||||||
logger: o.logger,
|
logger: o.logger,
|
||||||
nvidiaCDIHookPath: o.nvidiaCDIHookPath,
|
nvidiaCDIHookPath: o.nvidiaCDIHookPath,
|
||||||
targets: targets,
|
targets: targets,
|
||||||
mountsFrom: mounts,
|
|
||||||
symlinkChainLocator: o.symlinkChainLocator,
|
symlinkChainLocator: o.symlinkChainLocator,
|
||||||
resolveSymlink: o.resolveSymlink,
|
resolveSymlink: o.resolveSymlink,
|
||||||
}
|
}
|
||||||
@ -52,62 +48,12 @@ func (o tegraOptions) createCSVSymlinkHooks(targets []string, mounts discover.Di
|
|||||||
|
|
||||||
// Hooks returns a hook to create the symlinks from the required CSV files
|
// Hooks returns a hook to create the symlinks from the required CSV files
|
||||||
func (d symlinkHook) Hooks() ([]discover.Hook, error) {
|
func (d symlinkHook) Hooks() ([]discover.Hook, error) {
|
||||||
specificLinks, err := d.getSpecificLinks()
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to determine specific links: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
csvSymlinks := d.getCSVFileSymlinks()
|
|
||||||
|
|
||||||
return discover.CreateCreateSymlinkHook(
|
return discover.CreateCreateSymlinkHook(
|
||||||
d.nvidiaCDIHookPath,
|
d.nvidiaCDIHookPath,
|
||||||
append(csvSymlinks, specificLinks...),
|
d.getCSVFileSymlinks(),
|
||||||
).Hooks()
|
).Hooks()
|
||||||
}
|
}
|
||||||
|
|
||||||
// getSpecificLinks returns the required specic links that need to be created
|
|
||||||
func (d symlinkHook) getSpecificLinks() ([]string, error) {
|
|
||||||
mounts, err := d.mountsFrom.Mounts()
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to discover mounts for ldcache update: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
linkProcessed := make(map[string]bool)
|
|
||||||
var links []string
|
|
||||||
for _, m := range mounts {
|
|
||||||
var target string
|
|
||||||
var link string
|
|
||||||
|
|
||||||
lib := filepath.Base(m.Path)
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case strings.HasPrefix(lib, "libcuda.so"):
|
|
||||||
// XXX Many applications wrongly assume that libcuda.so exists (e.g. with dlopen).
|
|
||||||
target = "libcuda.so.1"
|
|
||||||
link = "libcuda.so"
|
|
||||||
case strings.HasPrefix(lib, "libGLX_nvidia.so"):
|
|
||||||
// XXX GLVND requires this symlink for indirect GLX support.
|
|
||||||
target = lib
|
|
||||||
link = "libGLX_indirect.so.0"
|
|
||||||
case strings.HasPrefix(lib, "libnvidia-opticalflow.so"):
|
|
||||||
// XXX Fix missing symlink for libnvidia-opticalflow.so.
|
|
||||||
target = "libnvidia-opticalflow.so.1"
|
|
||||||
link = "libnvidia-opticalflow.so"
|
|
||||||
default:
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if linkProcessed[link] {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
linkProcessed[link] = true
|
|
||||||
|
|
||||||
linkPath := filepath.Join(filepath.Dir(m.Path), link)
|
|
||||||
links = append(links, fmt.Sprintf("%v::%v", target, linkPath))
|
|
||||||
}
|
|
||||||
|
|
||||||
return links, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// getSymlinkCandidates returns a list of symlinks that are candidates for being created.
|
// getSymlinkCandidates returns a list of symlinks that are candidates for being created.
|
||||||
func (d symlinkHook) getSymlinkCandidates() []string {
|
func (d symlinkHook) getSymlinkCandidates() []string {
|
||||||
var candidates []string
|
var candidates []string
|
||||||
|
@ -97,11 +97,15 @@ func NewDriverLibraryDiscoverer(logger logger.Interface, driver *root.Driver, nv
|
|||||||
libraryPaths,
|
libraryPaths,
|
||||||
)
|
)
|
||||||
|
|
||||||
hooks, _ := discover.NewLDCacheUpdateHook(logger, libraries, nvidiaCDIHookPath, ldconfigPath)
|
updateLDCache, _ := discover.NewLDCacheUpdateHook(logger, libraries, nvidiaCDIHookPath, ldconfigPath)
|
||||||
|
|
||||||
d := discover.Merge(
|
d := discover.Merge(
|
||||||
libraries,
|
discover.WithDriverDotSoSymlinks(
|
||||||
hooks,
|
libraries,
|
||||||
|
version,
|
||||||
|
nvidiaCDIHookPath,
|
||||||
|
),
|
||||||
|
updateLDCache,
|
||||||
)
|
)
|
||||||
|
|
||||||
return d, nil
|
return d, nil
|
||||||
|
Loading…
Reference in New Issue
Block a user