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 }