Skip to content

Commit 558a836

Browse files
committed
choose innner UsrLibDir based on /etc/os-release
1 parent 92ea729 commit 558a836

File tree

2 files changed

+61
-36
lines changed

2 files changed

+61
-36
lines changed

cli/docker.go

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -621,9 +621,8 @@ func runDockerCVM(ctx context.Context, log slog.Logger, client dockerutil.Client
621621
if strings.HasPrefix(mountpoint, flags.hostUsrLibDir) {
622622
mountpoint = filepath.Join(
623623
// Note: we used to mount into /usr/lib, but this can change
624-
// based on the distro inside the container. We are essentially
625-
// mimicking the behavior of the nvidia container runtime.
626-
imgMeta.UsrLibDir,
624+
// based on the distro inside the container.
625+
imgMeta.UsrLibDir(),
627626
strings.TrimPrefix(mountpoint, strings.TrimSuffix(flags.hostUsrLibDir, "/")),
628627
)
629628
}

dockerutil/image.go

Lines changed: 59 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"encoding/json"
77
"fmt"
88
"io"
9+
goruntime "runtime"
910
"strings"
1011
"time"
1112

@@ -22,19 +23,28 @@ import (
2223

2324
const diskFullStorageDriver = "vfs"
2425

25-
// Adapted from github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/library.go
26-
// These are destination candidates for the /usr/lib directory in the container,
27-
// in order of priority.
28-
// Depending on the inner image, the desired location may vary.
29-
// Note that we are excluding some nvidia-specific directories here and also
30-
// include a fallback to /usr/lib.
31-
var usrLibCandidates = []string{
32-
"/usr/lib/x86_64-linux-gnu", // Debian uses a multiarch /usr/lib directory
33-
"/usr/lib/aarch64-linux-gnu", // Above but for arm64.
34-
"/usr/lib64", // Red Hat and friends.
35-
"/usr/lib", // Fallback.
26+
var usrLibMultiarchDir = map[string]string{
27+
"arm64": "/usr/lib/aarch64-linux-gnu",
28+
"amd64": "/usr/lib/x86_64-linux-gnu",
3629
}
3730

31+
// Adapted from https://github.com/NVIDIA/libnvidia-container/blob/v1.15.0/src/nvc_container.c#L152-L165
32+
var usrLibDirs = map[string]string{
33+
// Debian-based distros use a multi-arch directory.
34+
"debian": usrLibMultiarchDir[goruntime.GOARCH],
35+
"ubuntu": usrLibMultiarchDir[goruntime.GOARCH],
36+
// Fedora and Redhat use the standard /usr/lib64.
37+
"fedora": "/usr/lib64",
38+
"redhat": "/usr/lib64",
39+
// Fall back to the standard /usr/lib.
40+
"linux": "/usr/lib",
41+
}
42+
43+
// /etc/os-release is the standard location for system identification data on
44+
// Linux systems running systemd.
45+
// Ref: https://www.freedesktop.org/software/systemd/man/latest/os-release.html
46+
var etcOsRelease = "/etc/os-release"
47+
3848
type PullImageConfig struct {
3949
Client Client
4050
Image string
@@ -161,11 +171,11 @@ func processImagePullEvents(r io.Reader, fn ImagePullProgressFn) error {
161171
}
162172

163173
type ImageMetadata struct {
164-
UID string
165-
GID string
166-
HomeDir string
167-
HasInit bool
168-
UsrLibDir string
174+
UID string
175+
GID string
176+
HomeDir string
177+
HasInit bool
178+
OsReleaseID string
169179
}
170180

171181
// GetImageMetadata returns metadata about an image such as the UID/GID of the
@@ -240,32 +250,48 @@ func GetImageMetadata(ctx context.Context, client Client, img, username string)
240250
return ImageMetadata{}, xerrors.Errorf("no users returned for username %s", username)
241251
}
242252

243-
// Find the "best" usr lib directory for the container.
244-
var foundUsrLibDir string
245-
for _, candidate := range usrLibCandidates {
246-
_, err := ExecContainer(ctx, client, ExecConfig{
247-
ContainerID: inspect.ID,
248-
Cmd: "stat",
249-
Args: []string{candidate},
250-
})
251-
if err == nil {
252-
foundUsrLibDir = candidate
253+
// Read the /etc/os-release file to get the ID of the OS.
254+
out, err = ExecContainer(ctx, client, ExecConfig{
255+
ContainerID: inspect.ID,
256+
Cmd: "cat",
257+
Args: []string{etcOsRelease},
258+
})
259+
if err != nil {
260+
return ImageMetadata{}, xerrors.Errorf("read /etc/os-release: %w", err)
261+
}
262+
// We only care about the ID field.
263+
osReleaseID := ""
264+
for _, line := range strings.Split(string(out), "\n") {
265+
if strings.HasPrefix(line, "ID=") {
266+
osReleaseID = strings.TrimPrefix(line, "ID=")
267+
// The value may be quoted.
268+
osReleaseID = strings.Trim(osReleaseID, "\"")
253269
break
254270
}
255271
}
256-
if foundUsrLibDir == "" {
257-
return ImageMetadata{}, xerrors.Errorf("no eligible /usr/lib directory found in container")
272+
if osReleaseID == "" {
273+
// The default value is just "linux" if we can't find the ID.
274+
osReleaseID = "linux"
258275
}
259276

260277
return ImageMetadata{
261-
UID: users[0].Uid,
262-
GID: users[0].Gid,
263-
HomeDir: users[0].HomeDir,
264-
HasInit: initExists,
265-
UsrLibDir: foundUsrLibDir,
278+
UID: users[0].Uid,
279+
GID: users[0].Gid,
280+
HomeDir: users[0].HomeDir,
281+
HasInit: initExists,
282+
OsReleaseID: osReleaseID,
266283
}, nil
267284
}
268285

286+
// UsrLibDir returns the path to the /usr/lib directory for the given
287+
// operating system determined by the /etc/os-release file.
288+
func (im ImageMetadata) UsrLibDir() string {
289+
if val, ok := usrLibDirs[im.OsReleaseID]; ok {
290+
return val
291+
}
292+
return usrLibDirs["linux"] // fallback
293+
}
294+
269295
func DefaultLogImagePullFn(log buildlog.Logger) func(ImagePullEvent) error {
270296
var (
271297
// Avoid spamming too frequently, the messages can come quickly

0 commit comments

Comments
 (0)