mirror of
https://github.com/iLoveElysia/openbilibili.git
synced 2026-03-14 05:46:26 -05:00
162 lines
4.5 KiB
Go
162 lines
4.5 KiB
Go
|
|
/*
|
||
|
|
Copyright 2018 The Kubernetes Authors.
|
||
|
|
|
||
|
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
|
you may not use this file except in compliance with the License.
|
||
|
|
You may obtain a copy of the License at
|
||
|
|
|
||
|
|
http://www.apache.org/licenses/LICENSE-2.0
|
||
|
|
|
||
|
|
Unless required by applicable law or agreed to in writing, software
|
||
|
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
|
See the License for the specific language governing permissions and
|
||
|
|
limitations under the License.
|
||
|
|
*/
|
||
|
|
|
||
|
|
package clonerefs
|
||
|
|
|
||
|
|
import (
|
||
|
|
"encoding/json"
|
||
|
|
"fmt"
|
||
|
|
"io/ioutil"
|
||
|
|
"os"
|
||
|
|
"os/exec"
|
||
|
|
"path/filepath"
|
||
|
|
"strings"
|
||
|
|
"sync"
|
||
|
|
|
||
|
|
"github.com/sirupsen/logrus"
|
||
|
|
"k8s.io/test-infra/prow/kube"
|
||
|
|
"k8s.io/test-infra/prow/pod-utils/clone"
|
||
|
|
)
|
||
|
|
|
||
|
|
var cloneFunc = clone.Run
|
||
|
|
|
||
|
|
// Run clones the configured refs
|
||
|
|
func (o Options) Run() error {
|
||
|
|
var env []string
|
||
|
|
if len(o.KeyFiles) > 0 {
|
||
|
|
var err error
|
||
|
|
env, err = addSSHKeys(o.KeyFiles)
|
||
|
|
if err != nil {
|
||
|
|
logrus.WithError(err).Error("Failed to add SSH keys.")
|
||
|
|
// Continue on error. Clones will fail with an appropriate error message
|
||
|
|
// that initupload can consume whereas quitting without writing the clone
|
||
|
|
// record log is silent and results in an errored prow job instead of a
|
||
|
|
// failed one.
|
||
|
|
}
|
||
|
|
}
|
||
|
|
if len(o.HostFingerprints) > 0 {
|
||
|
|
if err := addHostFingerprints(o.HostFingerprints); err != nil {
|
||
|
|
logrus.WithError(err).Error("failed to add host fingerprints")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
var numWorkers int
|
||
|
|
if o.MaxParallelWorkers != 0 {
|
||
|
|
numWorkers = o.MaxParallelWorkers
|
||
|
|
} else {
|
||
|
|
numWorkers = len(o.GitRefs)
|
||
|
|
}
|
||
|
|
|
||
|
|
wg := &sync.WaitGroup{}
|
||
|
|
wg.Add(numWorkers)
|
||
|
|
|
||
|
|
input := make(chan kube.Refs)
|
||
|
|
output := make(chan clone.Record, len(o.GitRefs))
|
||
|
|
for i := 0; i < numWorkers; i++ {
|
||
|
|
go func() {
|
||
|
|
defer wg.Done()
|
||
|
|
for ref := range input {
|
||
|
|
output <- cloneFunc(ref, o.SrcRoot, o.GitUserName, o.GitUserEmail, o.CookiePath, env)
|
||
|
|
}
|
||
|
|
}()
|
||
|
|
}
|
||
|
|
|
||
|
|
for _, ref := range o.GitRefs {
|
||
|
|
input <- ref
|
||
|
|
}
|
||
|
|
|
||
|
|
close(input)
|
||
|
|
wg.Wait()
|
||
|
|
close(output)
|
||
|
|
|
||
|
|
var results []clone.Record
|
||
|
|
for record := range output {
|
||
|
|
results = append(results, record)
|
||
|
|
}
|
||
|
|
|
||
|
|
logData, err := json.Marshal(results)
|
||
|
|
if err != nil {
|
||
|
|
return fmt.Errorf("failed to marshal clone records: %v", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
if err := ioutil.WriteFile(o.Log, logData, 0755); err != nil {
|
||
|
|
return fmt.Errorf("failed to write clone records: %v", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
func addHostFingerprints(fingerprints []string) error {
|
||
|
|
path := filepath.Join(os.Getenv("HOME"), ".ssh", "known_hosts")
|
||
|
|
f, err := os.OpenFile(path, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||
|
|
if err != nil {
|
||
|
|
return fmt.Errorf("could not create/append to %s: %v", path, err)
|
||
|
|
}
|
||
|
|
if _, err := f.Write([]byte(strings.Join(fingerprints, "\n"))); err != nil {
|
||
|
|
return fmt.Errorf("failed to write fingerprints to %s: %v", path, err)
|
||
|
|
}
|
||
|
|
if err := f.Close(); err != nil {
|
||
|
|
return fmt.Errorf("failed to close %s: %v", path, err)
|
||
|
|
}
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
// addSSHKeys will start the ssh-agent and add all the specified
|
||
|
|
// keys, returning the ssh-agent environment variables for reuse
|
||
|
|
func addSSHKeys(paths []string) ([]string, error) {
|
||
|
|
vars, err := exec.Command("ssh-agent").CombinedOutput()
|
||
|
|
if err != nil {
|
||
|
|
return []string{}, fmt.Errorf("failed to start ssh-agent: %v", err)
|
||
|
|
}
|
||
|
|
logrus.Info("Started SSH agent")
|
||
|
|
// ssh-agent will output three lines of text, in the form:
|
||
|
|
// SSH_AUTH_SOCK=xxx; export SSH_AUTH_SOCK;
|
||
|
|
// SSH_AGENT_PID=xxx; export SSH_AGENT_PID;
|
||
|
|
// echo Agent pid xxx;
|
||
|
|
// We need to parse out the environment variables from that.
|
||
|
|
parts := strings.Split(string(vars), ";")
|
||
|
|
env := []string{strings.TrimSpace(parts[0]), strings.TrimSpace(parts[2])}
|
||
|
|
for _, keyPath := range paths {
|
||
|
|
// we can be given literal paths to keys or paths to dirs
|
||
|
|
// that are mounted from a secret, so we need to check which
|
||
|
|
// we have
|
||
|
|
if err := filepath.Walk(keyPath, func(path string, info os.FileInfo, err error) error {
|
||
|
|
if strings.HasPrefix(info.Name(), "..") {
|
||
|
|
// kubernetes volumes also include files we
|
||
|
|
// should not look be looking into for keys
|
||
|
|
if info.IsDir() {
|
||
|
|
return filepath.SkipDir
|
||
|
|
}
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
if info.IsDir() {
|
||
|
|
return nil
|
||
|
|
}
|
||
|
|
|
||
|
|
cmd := exec.Command("ssh-add", path)
|
||
|
|
cmd.Env = append(cmd.Env, env...)
|
||
|
|
if output, err := cmd.CombinedOutput(); err != nil {
|
||
|
|
return fmt.Errorf("failed to add ssh key at %s: %v: %s", path, err, output)
|
||
|
|
}
|
||
|
|
logrus.Infof("Added SSH key at %s", path)
|
||
|
|
return nil
|
||
|
|
}); err != nil {
|
||
|
|
return env, fmt.Errorf("error walking path %q: %v", keyPath, err)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return env, nil
|
||
|
|
}
|