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  }