blob: fabf8ea13d94f5080ea6f332673868c7e118cd88 [file]
package installer
import (
"bytes"
"fmt"
"os"
"os/exec"
"path/filepath"
"text/template"
log "github.com/golang/glog"
"golang.org/x/sys/unix"
)
const (
griddPathTmpl = `[Unit]
Description=Trigger the nvidia-gridd binary if it exists/changes
[Path]
PathExists={{.InstallDir}}/bin/nvidia-gridd
Unit=nvidia-gridd.service
[Install]
WantedBy=multi-user.target
`
griddServiceTmpl = `[Unit]
Description=Launches nvidia-gridd
ConditionPathExists={{.InstallDir}}/bin/nvidia-gridd
[Service]
Type=forking
Environment="LD_LIBRARY_PATH={{.InstallDir}}/gridd-libs"
ExecStart={{.InstallDir}}/bin/nvidia-gridd
Restart=on-failure
RestartSec=6s
[Install]
WantedBy=multi-user.target
`
persistencedPathTmpl = `[Unit]
Description=Trigger the nvidia-persistenced binary if it exists/changes
[Path]
PathExists={{.InstallDir}}/bin/nvidia-persistenced
Unit=nvidia-persistenced.service
[Install]
WantedBy=multi-user.target
`
persistencedServiceTmpl = `[Unit]
Description=Launches nvidia-persistenced
ConditionPathExists={{.InstallDir}}/bin/nvidia-persistenced
[Service]
Type=forking
ExecStart={{.InstallDir}}/bin/nvidia-persistenced
Restart=on-failure
RestartSec=6s
[Install]
WantedBy=multi-user.target
`
)
type sysdTemplateData struct {
InstallDir string
}
func writeTemplate(path string, tmplStr string, data sysdTemplateData) error {
tmpl, err := template.New(filepath.Base(path)).Parse(tmplStr)
if err != nil {
return err
}
var buf bytes.Buffer
if err := tmpl.Execute(&buf, data); err != nil {
return err
}
return os.WriteFile(path, buf.Bytes(), 0644)
}
// EnsureExecutable ensures that the installation directory on the host
// is executable by ensuring any noexec mounts are remounted with exec.
func EnsureExecutable(hostInstallDir, hostRootPath string) error {
containerViewOfHostDir := filepath.Join(hostRootPath, hostInstallDir)
var stat unix.Statfs_t
if err := unix.Statfs(containerViewOfHostDir, &stat); err != nil {
return fmt.Errorf("failed to statfs %s: %v", containerViewOfHostDir, err)
}
if stat.Flags&unix.ST_NOEXEC != 0 {
log.Infof("Target installation directory %s is mounted with noexec. Remounting as executable on the host.", hostInstallDir)
cmd := exec.Command("nsenter", "-t", "1", "-m", "mount", "--bind", hostInstallDir, hostInstallDir)
if out, err := cmd.CombinedOutput(); err != nil {
return fmt.Errorf("failed to bind mount %s on host: %v, out: %s", hostInstallDir, err, string(out))
}
cmd = exec.Command("nsenter", "-t", "1", "-m", "mount", "-o", "remount,exec", hostInstallDir)
if out, err := cmd.CombinedOutput(); err != nil {
return fmt.Errorf("failed to remount %s as executable on host: %v, out: %s", hostInstallDir, err, string(out))
}
} else {
log.V(2).Infof("Target installation directory %s is already executable.", hostInstallDir)
}
return nil
}
// SetupDaemons deploys systemd units for nvidia-persistenced and conditionally nvidia-gridd.
func SetupDaemons(hostInstallDir, hostRootPath string) error {
sysdDir := filepath.Join(hostRootPath, "etc/systemd/system")
if err := os.MkdirAll(sysdDir, 0755); err != nil {
return fmt.Errorf("failed to create systemd directory: %v", err)
}
data := sysdTemplateData{
InstallDir: hostInstallDir,
}
type unitDef struct {
name string
content string
}
units := []unitDef{
{"nvidia-persistenced.path", persistencedPathTmpl},
{"nvidia-persistenced.service", persistencedServiceTmpl},
}
isGrid := false
if _, err := os.Stat(filepath.Join(hostRootPath, hostInstallDir, "bin", "nvidia-gridd")); err == nil {
isGrid = true
}
if isGrid {
units = append(units, unitDef{"nvidia-gridd.path", griddPathTmpl})
units = append(units, unitDef{"nvidia-gridd.service", griddServiceTmpl})
}
for _, u := range units {
path := filepath.Join(sysdDir, u.name)
if err := writeTemplate(path, u.content, data); err != nil {
return fmt.Errorf("failed to write %s: %v", u.name, err)
}
}
cmd := exec.Command("chroot", hostRootPath, "systemctl", "daemon-reload")
if out, err := cmd.CombinedOutput(); err != nil {
log.Warningf("failed to daemon-reload: %v, out: %s", err, string(out))
} else {
startUnits := []string{"nvidia-persistenced.path"}
if isGrid {
startUnits = append(startUnits, "nvidia-gridd.path")
}
for _, unit := range startUnits {
cmd = exec.Command("chroot", hostRootPath, "systemctl", "start", unit)
if out, err := cmd.CombinedOutput(); err != nil {
log.Warningf("failed to start %s: %v, out: %s", unit, err, string(out))
}
}
log.Infof("Successfully setup NVIDIA systemd daemons")
}
return nil
}