| /* |
| Copyright 2014 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. |
| */ |
| |
| // User-interface for test-infra/kubetest/e2e.go |
| // Equivalent to go get -u k8s.io/test-infra/kubetest && kubetest "${@}" |
| package main |
| |
| import ( |
| "flag" |
| "fmt" |
| "go/build" |
| "log" |
| "os" |
| "os/exec" |
| "os/signal" |
| "path/filepath" |
| "strings" |
| "time" |
| ) |
| |
| type flags struct { |
| get bool |
| old time.Duration |
| args []string |
| } |
| |
| const ( |
| getDefault = true |
| oldDefault = 24 * time.Hour |
| ) |
| |
| func parse(args []string) (flags, error) { |
| fs := flag.NewFlagSet(args[0], flag.ContinueOnError) |
| get := fs.Bool("get", getDefault, "go get -u kubetest if old or not installed") |
| old := fs.Duration("old", oldDefault, "Consider kubetest old if it exceeds this") |
| verbose := fs.Bool("v", true, "this flag is translated to kubetest's --verbose-commands") |
| var a []string |
| if err := fs.Parse(args[1:]); err == flag.ErrHelp { |
| os.Stderr.WriteString(" -- kubetestArgs\n") |
| os.Stderr.WriteString(" All flags after -- are passed to the kubetest program\n") |
| return flags{}, err |
| } else if err != nil { |
| log.Print("NOTICE: go run hack/e2e.go is now a shim for test-infra/kubetest") |
| log.Printf(" Usage: go run hack/e2e.go [--get=%v] [--old=%v] -- [KUBETEST_ARGS]", getDefault, oldDefault) |
| log.Print(" The separator is required to use --get or --old flags") |
| log.Print(" The -- flag separator also suppresses this message") |
| a = args[len(args)-fs.NArg()-1:] |
| } else { |
| a = append(a, fmt.Sprintf("--verbose-commands=%t", *verbose)) |
| a = append(a, fs.Args()...) |
| } |
| return flags{*get, *old, a}, nil |
| } |
| |
| func main() { |
| log.SetFlags(log.LstdFlags | log.Lshortfile) |
| f, err := parse(os.Args) |
| if err != nil { |
| os.Exit(2) |
| } |
| t := newTester() |
| k, err := t.getKubetest(f.get, f.old) |
| if err != nil { |
| log.Fatalf("err: %v", err) |
| } |
| log.Printf("Calling kubetest %v...", strings.Join(f.args, " ")) |
| if err = t.wait(k, f.args...); err != nil { |
| log.Fatalf("err: %v", err) |
| } |
| log.Print("Done") |
| } |
| |
| func wait(cmd string, args ...string) error { |
| sigChannel := make(chan os.Signal, 1) |
| signal.Notify(sigChannel, os.Interrupt) |
| |
| c := exec.Command(cmd, args...) |
| c.Stdout = os.Stdout |
| c.Stderr = os.Stderr |
| if err := c.Start(); err != nil { |
| return err |
| } |
| go func() { |
| sig := <-sigChannel |
| if err := c.Process.Signal(sig); err != nil { |
| log.Fatalf("could not send %s signal %s: %v", cmd, sig, err) |
| } |
| }() |
| return c.Wait() |
| } |
| |
| // Struct that allows unit tests to override functionality. |
| type tester struct { |
| // os.Stat |
| stat func(string) (os.FileInfo, error) |
| // exec.LookPath |
| lookPath func(string) (string, error) |
| // build.Default.GOPATH |
| goPath string |
| wait func(string, ...string) error |
| } |
| |
| func newTester() tester { |
| return tester{os.Stat, exec.LookPath, build.Default.GOPATH, wait} |
| } |
| |
| // Try to find kubetest, either GOPATH/bin/kubetest or PATH |
| func (t tester) lookKubetest() (string, error) { |
| // Check for kubetest in GOPATH/bin |
| if t.goPath != "" { |
| p := filepath.Join(t.goPath, "bin", "kubetest") |
| _, err := t.stat(p) |
| if err == nil { |
| return p, nil |
| } |
| } |
| |
| // Check for kubetest in PATH |
| p, err := t.lookPath("kubetest") |
| return p, err |
| } |
| |
| // Upgrade if kubetest does not exist or has not been updated today |
| func (t tester) getKubetest(get bool, old time.Duration) (string, error) { |
| // Find kubetest installation |
| p, err := t.lookKubetest() |
| if err == nil && !get { |
| return p, nil // Installed, Skip update |
| } |
| if err == nil { |
| // Installed recently? |
| if s, err := t.stat(p); err != nil { |
| return p, err // Cannot stat |
| } else if time.Since(s.ModTime()) <= old { |
| return p, nil // Recently updated |
| } else if t.goPath == "" { |
| log.Print("Skipping kubetest upgrade because $GOPATH is empty") |
| return p, nil |
| } |
| log.Printf("The kubetest binary is older than %s.", old) |
| } |
| if t.goPath == "" { |
| return "", fmt.Errorf("Cannot install kubetest until $GOPATH is set") |
| } |
| log.Print("Updating kubetest binary...") |
| cmd := []string{"go", "get", "-u", "k8s.io/test-infra/kubetest"} |
| if err = t.wait(cmd[0], cmd[1:]...); err != nil { |
| return "", fmt.Errorf("%s: %v", strings.Join(cmd, " "), err) // Could not upgrade |
| } |
| if p, err = t.lookKubetest(); err != nil { |
| return "", err // Cannot find kubetest |
| } else if err = t.wait("touch", p); err != nil { |
| return "", err // Could not touch |
| } else { |
| return p, nil // Updated modtime |
| } |
| } |