| /* |
| * Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved. |
| * |
| * 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 e2e |
| |
| import ( |
| "bytes" |
| "fmt" |
| "text/template" |
| ) |
| |
| // dockerInstallTemplate is a template for installing the NVIDIA Container Toolkit |
| // on a host using Docker. |
| var dockerInstallTemplate = ` |
| #! /usr/bin/env bash |
| set -xe |
| |
| : ${IMAGE:={{.Image}}} |
| |
| # Create a temporary directory |
| TEMP_DIR="/tmp/ctk_e2e.$(date +%s)_$RANDOM" |
| mkdir -p "$TEMP_DIR" |
| |
| # Given that docker has an init function that checks for the existence of the |
| # nvidia-container-toolkit, we need to create a symlink to the nvidia-container-runtime-hook |
| # in the /usr/bin directory. |
| # See https://github.com/moby/moby/blob/20a05dabf44934447d1a66cdd616cc803b81d4e2/daemon/nvidia_linux.go#L32-L46 |
| sudo rm -f /usr/bin/nvidia-container-runtime-hook |
| sudo ln -s "$TEMP_DIR/toolkit/nvidia-container-runtime-hook" /usr/bin/nvidia-container-runtime-hook |
| |
| docker run --pid=host --rm -i --privileged \ |
| -v /:/host \ |
| -v /var/run/docker.sock:/var/run/docker.sock \ |
| -v "$TEMP_DIR:$TEMP_DIR" \ |
| -v /etc/docker:/config-root \ |
| ${IMAGE} \ |
| --root "$TEMP_DIR" \ |
| --runtime=docker \ |
| --config=/config-root/daemon.json \ |
| --driver-root=/ \ |
| --no-daemon \ |
| --restart-mode=systemd |
| ` |
| |
| type ToolkitInstaller struct { |
| runner Runner |
| template string |
| |
| Image string |
| } |
| |
| type installerOption func(*ToolkitInstaller) |
| |
| func WithRunner(r Runner) installerOption { |
| return func(i *ToolkitInstaller) { |
| i.runner = r |
| } |
| } |
| |
| func WithImage(image string) installerOption { |
| return func(i *ToolkitInstaller) { |
| i.Image = image |
| } |
| } |
| |
| func WithTemplate(template string) installerOption { |
| return func(i *ToolkitInstaller) { |
| i.template = template |
| } |
| } |
| |
| func NewToolkitInstaller(opts ...installerOption) (*ToolkitInstaller, error) { |
| i := &ToolkitInstaller{ |
| runner: localRunner{}, |
| template: dockerInstallTemplate, |
| } |
| |
| for _, opt := range opts { |
| opt(i) |
| } |
| |
| if i.Image == "" { |
| return nil, fmt.Errorf("image is required") |
| } |
| |
| return i, nil |
| } |
| |
| func (i *ToolkitInstaller) Install() error { |
| // Parse the combined template |
| tmpl, err := template.New("installScript").Parse(i.template) |
| if err != nil { |
| return fmt.Errorf("error parsing template: %w", err) |
| } |
| |
| // Execute the template |
| var renderedScript bytes.Buffer |
| err = tmpl.Execute(&renderedScript, i) |
| if err != nil { |
| return fmt.Errorf("error executing template: %w", err) |
| } |
| |
| _, _, err = i.runner.Run(renderedScript.String()) |
| return err |
| } |