Skip to content

Commit 0b28791

Browse files
committed
Fix update of ldcache on non-debian containers
This change ensures that the ldcache in a non-debian container includes libraries at /lib64 and /usr/lib64 when running on debian host. This is required because the system search paths do not include these folders by default resulting in a non-debian container missing system libraries from the ldcache. Signed-off-by: Evan Lezar <[email protected]>
1 parent a7a8df2 commit 0b28791

File tree

3 files changed

+48
-10
lines changed

3 files changed

+48
-10
lines changed

internal/ldconfig/ldconfig.go

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,8 @@ func NewRunner(id string, ldconfigPath string, containerRoot string, additionala
6767
// This struct is used to perform operations on the ldcache and libraries in a
6868
// particular root (e.g. a container).
6969
//
70-
// args[0] is the reexec initializer function name
70+
// args[0] is the reexec initializer function name and is required.
71+
//
7172
// The following flags are required:
7273
//
7374
// --ldconfig-path=LDCONFIG_PATH the path to ldconfig on the host
@@ -76,16 +77,20 @@ func NewRunner(id string, ldconfigPath string, containerRoot string, additionala
7677
// The following flags are optional:
7778
//
7879
// --is-debian-like-host Indicates that the host system is debian-based.
80+
// See https://github.com/NVIDIA/nvidia-container-toolkit/pull/1444
7981
//
8082
// The remaining args are folders where soname symlinks need to be created.
8183
func NewFromArgs(args ...string) (*Ldconfig, error) {
8284
if len(args) < 1 {
8385
return nil, fmt.Errorf("incorrect arguments: %v", args)
8486
}
85-
fs := flag.NewFlagSet(args[1], flag.ExitOnError)
87+
fs := flag.NewFlagSet("ldconfig-options", flag.ExitOnError)
8688
ldconfigPath := fs.String("ldconfig-path", "", "the path to ldconfig on the host")
8789
containerRoot := fs.String("container-root", "", "the path in which ldconfig must be run")
88-
isDebianLikeHost := fs.Bool("is-debian-like-host", false, "the hook is running from a Debian-like host")
90+
isDebianLikeHost := fs.Bool("is-debian-like-host", false, `indicates that the host system is debian-based.
91+
This allows us to handle the case where there are differences in behavior
92+
between the ldconfig from the host (as executed from an update-ldcache hook) and
93+
ldconfig in the container. Such differences include system search paths.`)
8994
if err := fs.Parse(args[1:]); err != nil {
9095
return nil, err
9196
}
@@ -116,7 +121,7 @@ func (l *Ldconfig) UpdateLDCache() error {
116121
// Explicitly specify using /etc/ld.so.conf since the host's ldconfig may
117122
// be configured to use a different config file by default.
118123
const topLevelLdsoconfFilePath = "/etc/ld.so.conf"
119-
filteredDirectories, err := l.filterDirectories(topLevelLdsoconfFilePath, l.directories...)
124+
filteredDirectories, ldconfigDirs, err := l.filterDirectories(topLevelLdsoconfFilePath, l.directories...)
120125
if err != nil {
121126
return err
122127
}
@@ -126,6 +131,19 @@ func (l *Ldconfig) UpdateLDCache() error {
126131
"-f", topLevelLdsoconfFilePath,
127132
"-C", "/etc/ld.so.cache",
128133
}
134+
// If we are running in a non-debian container on a debian host we also
135+
// need to add the system directories for non-debian hosts to the list of
136+
// folders processed by ldconfig.
137+
// We only do this if they are not already tracked, since the folders on
138+
// on the command line have a higher priority than folders in ld.so.conf.
139+
if l.isDebianLikeHost && !l.isDebianLikeContainer {
140+
for _, systemSearchPath := range l.getSystemSearchPaths() {
141+
if _, ok := ldconfigDirs[systemSearchPath]; ok {
142+
continue
143+
}
144+
args = append(args, "/lib64", "/usr/lib64")
145+
}
146+
}
129147

130148
if err := createLdsoconfdFile(ldsoconfdFilenamePattern, filteredDirectories...); err != nil {
131149
return fmt.Errorf("failed to update ld.so.conf.d: %w", err)
@@ -157,10 +175,10 @@ func (l *Ldconfig) prepareRoot() (string, error) {
157175
return ldconfigPath, nil
158176
}
159177

160-
func (l *Ldconfig) filterDirectories(configFilePath string, directories ...string) ([]string, error) {
178+
func (l *Ldconfig) filterDirectories(configFilePath string, directories ...string) ([]string, map[string]struct{}, error) {
161179
ldconfigDirs, err := l.getLdsoconfDirectories(configFilePath)
162180
if err != nil {
163-
return nil, err
181+
return nil, nil, err
164182
}
165183

166184
var filtered []string
@@ -169,8 +187,9 @@ func (l *Ldconfig) filterDirectories(configFilePath string, directories ...strin
169187
continue
170188
}
171189
filtered = append(filtered, d)
190+
ldconfigDirs[d] = struct{}{}
172191
}
173-
return filtered, nil
192+
return filtered, ldconfigDirs, nil
174193
}
175194

176195
// createLdsoconfdFile creates a file at /etc/ld.so.conf.d/.
@@ -218,7 +237,7 @@ func createLdsoconfdFile(pattern string, dirs ...string) error {
218237
// files that refer to the directory.
219238
func (l *Ldconfig) getLdsoconfDirectories(configFilePath string) (map[string]struct{}, error) {
220239
ldconfigDirs := make(map[string]struct{})
221-
for _, d := range l.getSystemSerachPaths() {
240+
for _, d := range l.getSystemSearchPaths() {
222241
ldconfigDirs[d] = struct{}{}
223242
}
224243

@@ -247,7 +266,7 @@ func (l *Ldconfig) getLdsoconfDirectories(configFilePath string) (map[string]str
247266
return ldconfigDirs, nil
248267
}
249268

250-
func (l *Ldconfig) getSystemSerachPaths() []string {
269+
func (l *Ldconfig) getSystemSearchPaths() []string {
251270
if l.isDebianLikeContainer {
252271
debianSystemSearchPaths()
253272
}

internal/ldconfig/ldconfig_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ include INCLUDED_PATTERN*
117117
l := &Ldconfig{
118118
isDebianLikeContainer: true,
119119
}
120-
filtered, err := l.filterDirectories(topLevelConfPath, tc.input...)
120+
filtered, _, err := l.filterDirectories(topLevelConfPath, tc.input...)
121121

122122
require.NoError(t, err)
123123
require.Equal(t, tc.expected, filtered)

tests/e2e/nvidia-container-toolkit_test.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -570,4 +570,23 @@ EOF`)
570570
Expect(output).To(Equal(expectedOutput))
571571
})
572572
})
573+
574+
When("running a ubi9 container", Ordered, func() {
575+
var (
576+
expectedOutput string
577+
)
578+
BeforeAll(func(ctx context.Context) {
579+
_, _, err := runner.Run(`docker pull redhat/ubi9`)
580+
Expect(err).ToNot(HaveOccurred())
581+
582+
expectedOutput, _, err = runner.Run(`docker run --rm --runtime=runc redhat/ubi9 bash -c "ldconfig -p | grep libc.so."`)
583+
Expect(err).ToNot(HaveOccurred())
584+
})
585+
586+
It("should include the system libraries when using the nvidia-container-runtime", func(ctx context.Context) {
587+
output, _, err := runner.Run(`docker run --rm --runtime=nvidia -e NVIDIA_VISIBLE_DEVICES=all redhat/ubi9 bash -c "ldconfig -p | grep libc.so."`)
588+
Expect(err).ToNot(HaveOccurred())
589+
Expect(output).To(Equal(expectedOutput))
590+
})
591+
})
573592
})

0 commit comments

Comments
 (0)