github.com/yrj2011/jx-test-infra@v0.0.0-20190529031832-7a2065ee98eb/prow/clonerefs/run.go (about) 1 /* 2 Copyright 2018 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package clonerefs 18 19 import ( 20 "encoding/json" 21 "fmt" 22 "io/ioutil" 23 "os" 24 "os/exec" 25 "path/filepath" 26 "strings" 27 "sync" 28 29 "github.com/sirupsen/logrus" 30 "k8s.io/test-infra/prow/kube" 31 "k8s.io/test-infra/prow/pod-utils/clone" 32 ) 33 34 // Run clones the configured refs 35 func (o Options) Run() error { 36 var env []string 37 if len(o.KeyFiles) > 0 { 38 var err error 39 env, err = addSSHKeys(o.KeyFiles) 40 if err != nil { 41 logrus.WithError(err).Error("Failed to add SSH keys.") 42 // Continue on error. Clones will fail with an appropriate error message 43 // that initupload can consume whereas quiting without writing the clone 44 // record log is silent and results in an errored prow job instead of a 45 // failed one. 46 } 47 } 48 49 var numWorkers int 50 if o.MaxParallelWorkers != 0 { 51 numWorkers = o.MaxParallelWorkers 52 } else { 53 numWorkers = len(o.GitRefs) 54 } 55 56 wg := &sync.WaitGroup{} 57 wg.Add(numWorkers) 58 59 input := make(chan *kube.Refs) 60 output := make(chan clone.Record, len(o.GitRefs)) 61 for i := 0; i < numWorkers; i++ { 62 go func() { 63 defer wg.Done() 64 for ref := range input { 65 output <- clone.Run(ref, o.SrcRoot, o.GitUserName, o.GitUserEmail, env) 66 } 67 }() 68 } 69 70 for _, ref := range o.GitRefs { 71 input <- ref 72 } 73 74 close(input) 75 wg.Wait() 76 close(output) 77 78 var results []clone.Record 79 for record := range output { 80 results = append(results, record) 81 } 82 83 logData, err := json.Marshal(results) 84 if err != nil { 85 return fmt.Errorf("failed to marshal clone records: %v", err) 86 } 87 88 if err := ioutil.WriteFile(o.Log, logData, 0755); err != nil { 89 return fmt.Errorf("failed to write clone records: %v", err) 90 } 91 92 return nil 93 } 94 95 // addSSHKeys will start the ssh-agent and add all the specified 96 // keys, returning the ssh-agent environment variables for reuse 97 func addSSHKeys(paths []string) ([]string, error) { 98 vars, err := exec.Command("ssh-agent").CombinedOutput() 99 if err != nil { 100 return []string{}, fmt.Errorf("failed to start ssh-agent: %v", err) 101 } 102 logrus.Info("Started SSH agent") 103 // ssh-agent will output three lines of text, in the form: 104 // SSH_AUTH_SOCK=xxx; export SSH_AUTH_SOCK; 105 // SSH_AGENT_PID=xxx; export SSH_AGENT_PID; 106 // echo Agent pid xxx; 107 // We need to parse out the environment variables from that. 108 parts := strings.Split(string(vars), ";") 109 env := []string{strings.TrimSpace(parts[0]), strings.TrimSpace(parts[2])} 110 for _, keyPath := range paths { 111 // we can be given literal paths to keys or paths to dirs 112 // that are mounted from a secret, so we need to check which 113 // we have 114 if err := filepath.Walk(keyPath, func(path string, info os.FileInfo, err error) error { 115 if strings.HasPrefix(info.Name(), "..") { 116 // kubernetes volumes also include files we 117 // should not look be looking into for keys 118 if info.IsDir() { 119 return filepath.SkipDir 120 } 121 return nil 122 } 123 if info.IsDir() { 124 return nil 125 } 126 127 cmd := exec.Command("ssh-add", path) 128 cmd.Env = append(cmd.Env, env...) 129 if output, err := cmd.CombinedOutput(); err != nil { 130 return fmt.Errorf("failed to add ssh key at %s: %v: %s", path, err, output) 131 } 132 logrus.Infof("Added SSH key at %s", path) 133 return nil 134 }); err != nil { 135 return env, fmt.Errorf("error walking path %q: %v", keyPath, err) 136 } 137 } 138 return env, nil 139 }