Skip to content

Commit 4e4381f

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 9b9ae07 commit 4e4381f

File tree

3 files changed

+46
-8
lines changed

3 files changed

+46
-8
lines changed

internal/ldconfig/ldconfig.go

Lines changed: 26 additions & 7 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
}
@@ -118,7 +123,7 @@ func (l *Ldconfig) UpdateLDCache() error {
118123
// Explicitly specify using /etc/ld.so.conf since the host's ldconfig may
119124
// be configured to use a different config file by default.
120125
const topLevelLdsoconfFilePath = "/etc/ld.so.conf"
121-
filteredDirectories, err := l.filterDirectories(topLevelLdsoconfFilePath, l.directories...)
126+
filteredDirectories, ldconfigDirs, err := l.filterDirectories(topLevelLdsoconfFilePath, l.directories...)
122127
if err != nil {
123128
return err
124129
}
@@ -128,6 +133,19 @@ func (l *Ldconfig) UpdateLDCache() error {
128133
"-f", topLevelLdsoconfFilePath,
129134
"-C", "/etc/ld.so.cache",
130135
}
136+
// If we are running in a non-debian container on a debian host we also
137+
// need to add the system directories for non-debian hosts to the list of
138+
// folders processed by ldconfig.
139+
// We only do this if they are not already tracked, since the folders on
140+
// on the command line have a higher priority than folders in ld.so.conf.
141+
if l.isDebianLikeHost && !l.isDebianLikeContainer {
142+
for _, systemSearchPath := range l.getSystemSearchPaths() {
143+
if _, ok := ldconfigDirs[systemSearchPath]; ok {
144+
continue
145+
}
146+
args = append(args, systemSearchPath)
147+
}
148+
}
131149

132150
if err := createLdsoconfdFile(ldsoconfdFilenamePattern, filteredDirectories...); err != nil {
133151
return fmt.Errorf("failed to update ld.so.conf.d: %w", err)
@@ -165,10 +183,10 @@ func (l *Ldconfig) prepareRoot() (string, error) {
165183
return ldconfigPath, nil
166184
}
167185

168-
func (l *Ldconfig) filterDirectories(configFilePath string, directories ...string) ([]string, error) {
186+
func (l *Ldconfig) filterDirectories(configFilePath string, directories ...string) ([]string, map[string]struct{}, error) {
169187
ldconfigDirs, err := l.getLdsoconfDirectories(configFilePath)
170188
if err != nil {
171-
return nil, err
189+
return nil, nil, err
172190
}
173191

174192
var filtered []string
@@ -177,8 +195,9 @@ func (l *Ldconfig) filterDirectories(configFilePath string, directories ...strin
177195
continue
178196
}
179197
filtered = append(filtered, d)
198+
ldconfigDirs[d] = struct{}{}
180199
}
181-
return filtered, nil
200+
return filtered, ldconfigDirs, nil
182201
}
183202

184203
// createLdsoconfdFile creates a file at /etc/ld.so.conf.d/.

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)