-
Notifications
You must be signed in to change notification settings - Fork 361
Ensure that libcuda.so is in the ldcache #947
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
/** | ||
# SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved. | ||
# SPDX-License-Identifier: Apache-2.0 | ||
# | ||
# 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 create_soname_symlinks | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
"log" | ||
"os" | ||
|
||
"github.com/moby/sys/reexec" | ||
"github.com/urfave/cli/v2" | ||
|
||
"github.com/NVIDIA/nvidia-container-toolkit/internal/ldconfig" | ||
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger" | ||
"github.com/NVIDIA/nvidia-container-toolkit/internal/oci" | ||
) | ||
|
||
const ( | ||
reexecUpdateLdCacheCommandName = "reexec-create-soname-symlinks" | ||
) | ||
|
||
type command struct { | ||
logger logger.Interface | ||
} | ||
|
||
type options struct { | ||
folders cli.StringSlice | ||
ldconfigPath string | ||
containerSpec string | ||
} | ||
|
||
func init() { | ||
reexec.Register(reexecUpdateLdCacheCommandName, createSonameSymlinksHandler) | ||
if reexec.Init() { | ||
os.Exit(0) | ||
} | ||
} | ||
|
||
// NewCommand constructs an create-soname-symlinks command with the specified logger | ||
func NewCommand(logger logger.Interface) *cli.Command { | ||
c := command{ | ||
logger: logger, | ||
} | ||
return c.build() | ||
} | ||
|
||
// build the create-soname-symlinks command | ||
func (m command) build() *cli.Command { | ||
cfg := options{} | ||
|
||
// Create the 'create-soname-symlinks' command | ||
c := cli.Command{ | ||
Name: "create-soname-symlinks", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @klueska I elected to add a new hook entirely instead of modifying the existing |
||
Usage: "Create soname symlinks libraries in specified directories", | ||
Before: func(c *cli.Context) error { | ||
return m.validateFlags(c, &cfg) | ||
}, | ||
Action: func(c *cli.Context) error { | ||
return m.run(c, &cfg) | ||
}, | ||
} | ||
|
||
c.Flags = []cli.Flag{ | ||
&cli.StringSliceFlag{ | ||
Name: "folder", | ||
Usage: "Specify a directory to generate soname symlinks in. Can be specified multiple times", | ||
Destination: &cfg.folders, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. and here |
||
}, | ||
&cli.StringFlag{ | ||
Name: "ldconfig-path", | ||
Usage: "Specify the path to ldconfig on the host", | ||
Destination: &cfg.ldconfigPath, | ||
Value: "/sbin/ldconfig", | ||
}, | ||
&cli.StringFlag{ | ||
Name: "container-spec", | ||
Usage: "Specify the path to the OCI container spec. If empty or '-' the spec will be read from STDIN", | ||
Destination: &cfg.containerSpec, | ||
}, | ||
} | ||
|
||
return &c | ||
} | ||
|
||
func (m command) validateFlags(c *cli.Context, cfg *options) error { | ||
if cfg.ldconfigPath == "" { | ||
return errors.New("ldconfig-path must be specified") | ||
} | ||
return nil | ||
} | ||
|
||
func (m command) run(c *cli.Context, cfg *options) error { | ||
s, err := oci.LoadContainerState(cfg.containerSpec) | ||
if err != nil { | ||
return fmt.Errorf("failed to load container state: %v", err) | ||
} | ||
|
||
containerRootDir, err := s.GetContainerRoot() | ||
if err != nil || containerRootDir == "" || containerRootDir == "/" { | ||
return fmt.Errorf("failed to determined container root: %v", err) | ||
} | ||
|
||
cmd, err := ldconfig.NewRunner( | ||
reexecUpdateLdCacheCommandName, | ||
cfg.ldconfigPath, | ||
containerRootDir, | ||
cfg.folders.Value()..., | ||
) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
return cmd.Run() | ||
} | ||
|
||
// createSonameSymlinksHandler wraps createSonameSymlinks with error handling. | ||
func createSonameSymlinksHandler() { | ||
if err := createSonameSymlinks(os.Args); err != nil { | ||
log.Printf("Error updating ldcache: %v", err) | ||
os.Exit(1) | ||
} | ||
} | ||
|
||
// createSonameSymlinks ensures that soname symlinks are created in the | ||
// specified directories. | ||
// It is invoked from a reexec'd handler and provides namespace isolation for | ||
// the operations performed by this hook. At the point where this is invoked, | ||
// we are in a new mount namespace that is cloned from the parent. | ||
// | ||
// args[0] is the reexec initializer function name | ||
// args[1] is the path of the ldconfig binary on the host | ||
// args[2] is the container root directory | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we use directory here, I guess this is a good clue on how to define the discussion above. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This directory is different from the other directories that we're talking about. |
||
// The remaining args are directories where soname symlinks need to be created. | ||
func createSonameSymlinks(args []string) error { | ||
if len(args) < 3 { | ||
return fmt.Errorf("incorrect arguments: %v", args) | ||
} | ||
hostLdconfigPath := args[1] | ||
containerRootDirPath := args[2] | ||
|
||
ldconfig, err := ldconfig.New( | ||
hostLdconfigPath, | ||
containerRootDirPath, | ||
) | ||
if err != nil { | ||
return fmt.Errorf("failed to construct ldconfig runner: %w", err) | ||
} | ||
|
||
return ldconfig.CreateSonameSymlinks(args[3:]...) | ||
} |
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
directoryPaths
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
agree with Jan-P Directory is a much nicer call to Folder.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These options are filled by the CLI. A convention that I use is that the member matches (with the exception of plurality if required) the primary flag. Since the CLI argument is
--folder
(and can be repeated), I want to keep thisfolders
.