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  }