X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/b1daec9a928eefbc71d8b7368b148fa7b04bf32d..03a0562aedc85d2f5fd3ded8830e8948051c0331:/lib/crunchrun/singularity.go diff --git a/lib/crunchrun/singularity.go b/lib/crunchrun/singularity.go index 61fecad0a1..879c46c898 100644 --- a/lib/crunchrun/singularity.go +++ b/lib/crunchrun/singularity.go @@ -10,6 +10,7 @@ import ( "os" "os/exec" "sort" + "strings" "syscall" "time" @@ -36,6 +37,14 @@ func newSingularityExecutor(logf func(string, ...interface{})) (*singularityExec }, nil } +func (e *singularityExecutor) Runtime() string { + buf, err := exec.Command("singularity", "--version").CombinedOutput() + if err != nil { + return "singularity (unknown version)" + } + return strings.TrimSuffix(string(buf), "\n") +} + func (e *singularityExecutor) getOrCreateProject(ownerUuid string, name string, containerClient *arvados.Client) (*arvados.Group, error) { var gp arvados.GroupList err := containerClient.RequestAndDecode(&gp, @@ -158,7 +167,22 @@ func (e *singularityExecutor) LoadImage(dockerImageID string, imageTarballPath s return err } + // Set up a cache and tmp dir for singularity build + err = os.Mkdir(e.tmpdir+"/cache", 0700) + if err != nil { + return err + } + defer os.RemoveAll(e.tmpdir + "/cache") + err = os.Mkdir(e.tmpdir+"/tmp", 0700) + if err != nil { + return err + } + defer os.RemoveAll(e.tmpdir + "/tmp") + build := exec.Command("singularity", "build", imageFilename, "docker-archive://"+e.tmpdir+"/image.tar") + build.Env = os.Environ() + build.Env = append(build.Env, "SINGULARITY_CACHEDIR="+e.tmpdir+"/cache") + build.Env = append(build.Env, "SINGULARITY_TMPDIR="+e.tmpdir+"/tmp") e.logf("%v", build.Args) out, err := build.CombinedOutput() // INFO: Starting build... @@ -224,11 +248,16 @@ func (e *singularityExecutor) Create(spec containerSpec) error { return nil } -func (e *singularityExecutor) Start() error { - args := []string{"singularity", "exec", "--containall", "--no-home", "--cleanenv", "--pwd", e.spec.WorkingDir} +func (e *singularityExecutor) execCmd(path string) *exec.Cmd { + args := []string{path, "exec", "--containall", "--cleanenv", "--pwd", e.spec.WorkingDir} if !e.spec.EnableNetwork { args = append(args, "--net", "--network=none") } + + if e.spec.CUDADeviceCount != 0 { + args = append(args, "--nv") + } + readonlyflag := map[bool]string{ false: "rw", true: "ro", @@ -240,7 +269,12 @@ func (e *singularityExecutor) Start() error { sort.Strings(binds) for _, path := range binds { mount := e.spec.BindMounts[path] - args = append(args, "--bind", mount.HostPath+":"+path+":"+readonlyflag[mount.ReadOnly]) + if path == e.spec.Env["HOME"] { + // Singularity treates $HOME as special case + args = append(args, "--home", mount.HostPath+":"+path) + } else { + args = append(args, "--bind", mount.HostPath+":"+path+":"+readonlyflag[mount.ReadOnly]) + } } // This is for singularity 3.5.2. There are some behaviors @@ -250,21 +284,26 @@ func (e *singularityExecutor) Start() error { env := make([]string, 0, len(e.spec.Env)) for k, v := range e.spec.Env { if k == "HOME" { - // $HOME is a special case - args = append(args, "--home="+v) - } else { - env = append(env, "SINGULARITYENV_"+k+"="+v) + // Singularity treates $HOME as special case, this is handled + // with --home above + continue } + env = append(env, "SINGULARITYENV_"+k+"="+v) + } + + // Singularity always makes all nvidia devices visible to the + // container. If a resource manager such as slurm or LSF told + // us to select specific devices we need to propagate that. + if cudaVisibleDevices := os.Getenv("CUDA_VISIBLE_DEVICES"); cudaVisibleDevices != "" { + // If a resource manager such as slurm or LSF told + // us to select specific devices we need to propagate that. + env = append(env, "SINGULARITYENV_CUDA_VISIBLE_DEVICES="+cudaVisibleDevices) } args = append(args, e.imageFilename) args = append(args, e.spec.Command...) - path, err := exec.LookPath(args[0]) - if err != nil { - return err - } - child := &exec.Cmd{ + return &exec.Cmd{ Path: path, Args: args, Env: env, @@ -272,6 +311,14 @@ func (e *singularityExecutor) Start() error { Stdout: e.spec.Stdout, Stderr: e.spec.Stderr, } +} + +func (e *singularityExecutor) Start() error { + path, err := exec.LookPath("singularity") + if err != nil { + return err + } + child := e.execCmd(path) err = child.Start() if err != nil { return err