github.com/anth0d/nomad@v0.0.0-20221214183521-ae3a0a2cad06/client/allocrunner/taskrunner/getter/util.go (about)

     1  package getter
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"net/http"
     7  	"net/url"
     8  	"os"
     9  	"os/exec"
    10  	"path/filepath"
    11  	"sort"
    12  	"strings"
    13  	"unicode"
    14  
    15  	"github.com/hashicorp/go-getter"
    16  	"github.com/hashicorp/nomad/client/interfaces"
    17  	"github.com/hashicorp/nomad/helper/subproc"
    18  	"github.com/hashicorp/nomad/nomad/structs"
    19  )
    20  
    21  const (
    22  	// githubPrefixSSH is the prefix for downloading via git using ssh from GitHub.
    23  	githubPrefixSSH = "git@github.com:"
    24  )
    25  
    26  func getURL(taskEnv interfaces.EnvReplacer, artifact *structs.TaskArtifact) (string, error) {
    27  	source := taskEnv.ReplaceEnv(artifact.GetterSource)
    28  
    29  	// fixup GitHub SSH URL such as git@github.com:hashicorp/nomad.git
    30  	gitSSH := false
    31  	if strings.HasPrefix(source, githubPrefixSSH) {
    32  		gitSSH = true
    33  		source = source[len(githubPrefixSSH):]
    34  	}
    35  
    36  	u, err := url.Parse(source)
    37  	if err != nil {
    38  		return "", &Error{
    39  			URL:         artifact.GetterSource,
    40  			Err:         fmt.Errorf("failed to parse source URL %q: %v", artifact.GetterSource, err),
    41  			Recoverable: false,
    42  		}
    43  	}
    44  
    45  	// build the URL by substituting as necessary
    46  	q := u.Query()
    47  	for k, v := range artifact.GetterOptions {
    48  		q.Set(k, taskEnv.ReplaceEnv(v))
    49  	}
    50  	u.RawQuery = q.Encode()
    51  
    52  	// add the prefix back if necessary
    53  	sourceURL := u.String()
    54  	if gitSSH {
    55  		sourceURL = fmt.Sprintf("%s%s", githubPrefixSSH, sourceURL)
    56  	}
    57  
    58  	return sourceURL, nil
    59  }
    60  
    61  func getDestination(env interfaces.EnvReplacer, artifact *structs.TaskArtifact) (string, error) {
    62  	destination, escapes := env.ClientPath(artifact.RelativeDest, true)
    63  	if escapes {
    64  		return "", &Error{
    65  			URL:         artifact.GetterSource,
    66  			Err:         fmt.Errorf("artifact destination path escapes alloc directory"),
    67  			Recoverable: false,
    68  		}
    69  	}
    70  	return destination, nil
    71  }
    72  
    73  func getMode(artifact *structs.TaskArtifact) getter.ClientMode {
    74  	switch artifact.GetterMode {
    75  	case structs.GetterModeFile:
    76  		return getter.ClientModeFile
    77  	case structs.GetterModeDir:
    78  		return getter.ClientModeDir
    79  	default:
    80  		return getter.ClientModeAny
    81  	}
    82  }
    83  
    84  func getHeaders(env interfaces.EnvReplacer, artifact *structs.TaskArtifact) map[string][]string {
    85  	m := artifact.GetterHeaders
    86  	if len(m) == 0 {
    87  		return nil
    88  	}
    89  	headers := make(http.Header, len(m))
    90  	for k, v := range m {
    91  		headers.Set(k, env.ReplaceEnv(v))
    92  	}
    93  	return headers
    94  }
    95  
    96  func getTaskDir(env interfaces.EnvReplacer) string {
    97  	p, _ := env.ClientPath("stub", false)
    98  	return filepath.Dir(p)
    99  }
   100  
   101  // environment merges the default minimal environment per-OS with the set of
   102  // environment variables configured to be inherited from the Client
   103  func environment(taskDir string, inherit string) []string {
   104  	chomp := func(s string) []string {
   105  		return strings.FieldsFunc(s, func(c rune) bool {
   106  			return c == ',' || unicode.IsSpace(c)
   107  		})
   108  	}
   109  	env := defaultEnvironment(taskDir)
   110  	for _, name := range chomp(inherit) {
   111  		env[name] = os.Getenv(name)
   112  	}
   113  	result := make([]string, 0, len(env))
   114  	for k, v := range env {
   115  		result = append(result, fmt.Sprintf("%s=%s", k, v))
   116  	}
   117  	sort.Strings(result)
   118  	return result
   119  }
   120  
   121  func (s *Sandbox) runCmd(env *parameters) error {
   122  	// find the nomad process
   123  	bin := subproc.Self()
   124  
   125  	// final method of ensuring subprocess termination
   126  	ctx, cancel := subproc.Context(env.deadline())
   127  	defer cancel()
   128  
   129  	// start the subprocess, passing in parameters via stdin
   130  	output := new(bytes.Buffer)
   131  	cmd := exec.CommandContext(ctx, bin, SubCommand)
   132  	cmd.Env = environment(env.TaskDir, env.SetEnvironmentVariables)
   133  	cmd.Stdin = env.reader()
   134  	cmd.Stdout = output
   135  	cmd.Stderr = output
   136  	cmd.SysProcAttr = attributes()
   137  
   138  	// start & wait for the subprocess to terminate
   139  	if err := cmd.Run(); err != nil {
   140  		subproc.Log(output, s.logger.Error)
   141  		return &Error{
   142  			URL:         env.Source,
   143  			Err:         fmt.Errorf("getter subprocess failed: %v", err),
   144  			Recoverable: true,
   145  		}
   146  	}
   147  	subproc.Log(output, s.logger.Debug)
   148  	return nil
   149  }