github.com/apptainer/singularity@v3.1.1+incompatible/internal/pkg/runtime/engines/imgbuild/process.go (about) 1 // Copyright (c) 2019, Sylabs Inc. All rights reserved. 2 // This software is licensed under a 3-clause BSD license. Please consult the 3 // LICENSE.md file distributed with the sources of this project regarding your 4 // rights to use or distribute this software. 5 6 package imgbuild 7 8 import ( 9 "fmt" 10 "net" 11 "os" 12 "os/exec" 13 "strings" 14 "syscall" 15 16 "github.com/opencontainers/runtime-tools/generate" 17 "github.com/sylabs/singularity/internal/pkg/sylog" 18 "github.com/sylabs/singularity/internal/pkg/util/env" 19 ) 20 21 // StartProcess runs the %post script 22 func (e *EngineOperations) StartProcess(masterConn net.Conn) error { 23 24 // clean environment in which %post and %test scripts are run in 25 e.cleanEnv() 26 27 if e.EngineConfig.RunSection("post") && e.EngineConfig.Recipe.BuildData.Post != "" { 28 // Run %post script here 29 post := exec.Command("/bin/sh", "-cex", e.EngineConfig.Recipe.BuildData.Post) 30 post.Env = e.EngineConfig.OciConfig.Process.Env 31 post.Stdout = os.Stdout 32 post.Stderr = os.Stderr 33 34 sylog.Infof("Running post scriptlet\n") 35 if err := post.Start(); err != nil { 36 sylog.Fatalf("failed to start %%post proc: %v\n", err) 37 } 38 if err := post.Wait(); err != nil { 39 sylog.Fatalf("post proc: %v\n", err) 40 } 41 } 42 43 if e.EngineConfig.RunSection("test") { 44 if !e.EngineConfig.Opts.NoTest && e.EngineConfig.Recipe.BuildData.Test != "" { 45 // Run %test script 46 test := exec.Command("/bin/sh", "-cex", e.EngineConfig.Recipe.BuildData.Test) 47 test.Stdout = os.Stdout 48 test.Stderr = os.Stderr 49 50 sylog.Infof("Running test scriptlet\n") 51 if err := test.Start(); err != nil { 52 sylog.Fatalf("failed to start %%test proc: %v\n", err) 53 } 54 if err := test.Wait(); err != nil { 55 sylog.Fatalf("test proc: %v\n", err) 56 } 57 } 58 } 59 60 os.Exit(0) 61 return nil 62 } 63 64 // MonitorContainer is responsible for waiting on container process 65 func (e *EngineOperations) MonitorContainer(pid int, signals chan os.Signal) (syscall.WaitStatus, error) { 66 var status syscall.WaitStatus 67 68 for { 69 s := <-signals 70 switch s { 71 case syscall.SIGCHLD: 72 if wpid, err := syscall.Wait4(pid, &status, syscall.WNOHANG, nil); err != nil { 73 return status, fmt.Errorf("error while waiting child: %s", err) 74 } else if wpid != pid { 75 continue 76 } 77 return status, nil 78 default: 79 if err := syscall.Kill(pid, s.(syscall.Signal)); err != nil { 80 return status, fmt.Errorf("interrupted by signal %s", s.String()) 81 } 82 } 83 } 84 } 85 86 // CleanupContainer _ 87 func (e *EngineOperations) CleanupContainer(fatal error, status syscall.WaitStatus) error { 88 return nil 89 } 90 91 // PostStartProcess actually does nothing for build engine 92 func (e *EngineOperations) PostStartProcess(pid int) error { 93 return nil 94 } 95 96 func (e *EngineOperations) cleanEnv() { 97 generator := generate.Generator{Config: &e.EngineConfig.OciConfig.Spec} 98 99 // copy and cache environment 100 environment := e.EngineConfig.OciConfig.Spec.Process.Env 101 102 // clean environment 103 e.EngineConfig.OciConfig.Spec.Process.Env = nil 104 105 // add relevant environment variables back 106 env.SetContainerEnv(&generator, environment, true, "") 107 108 // expose build specific environment variables for scripts 109 for _, envVar := range environment { 110 e := strings.SplitN(envVar, "=", 2) 111 if e[0] == "SINGULARITY_ROOTFS" || e[0] == "SINGULARITY_ENVIRONMENT" { 112 generator.Config.Process.Env = append(generator.Config.Process.Env, envVar) 113 } 114 115 } 116 117 }