e2e.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. /*
  2. Copyright 2014 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. // User-interface for test-infra/kubetest/e2e.go
  14. // Equivalent to go get -u k8s.io/test-infra/kubetest && kubetest "${@}"
  15. package main
  16. import (
  17. "flag"
  18. "fmt"
  19. "go/build"
  20. "log"
  21. "os"
  22. "os/exec"
  23. "os/signal"
  24. "path/filepath"
  25. "strings"
  26. "time"
  27. )
  28. type flags struct {
  29. get bool
  30. old time.Duration
  31. args []string
  32. }
  33. const (
  34. getDefault = true
  35. oldDefault = 24 * time.Hour
  36. )
  37. func parse(args []string) (flags, error) {
  38. fs := flag.NewFlagSet(args[0], flag.ContinueOnError)
  39. get := fs.Bool("get", getDefault, "go get -u kubetest if old or not installed")
  40. old := fs.Duration("old", oldDefault, "Consider kubetest old if it exceeds this")
  41. verbose := fs.Bool("v", true, "this flag is translated to kubetest's --verbose-commands")
  42. var a []string
  43. if err := fs.Parse(args[1:]); err == flag.ErrHelp {
  44. os.Stderr.WriteString(" -- kubetestArgs\n")
  45. os.Stderr.WriteString(" All flags after -- are passed to the kubetest program\n")
  46. return flags{}, err
  47. } else if err != nil {
  48. log.Print("NOTICE: go run hack/e2e.go is now a shim for test-infra/kubetest")
  49. log.Printf(" Usage: go run hack/e2e.go [--get=%v] [--old=%v] -- [KUBETEST_ARGS]", getDefault, oldDefault)
  50. log.Print(" The separator is required to use --get or --old flags")
  51. log.Print(" The -- flag separator also suppresses this message")
  52. a = args[len(args)-fs.NArg()-1:]
  53. } else {
  54. a = append(a, fmt.Sprintf("--verbose-commands=%t", *verbose))
  55. a = append(a, fs.Args()...)
  56. }
  57. return flags{*get, *old, a}, nil
  58. }
  59. func main() {
  60. log.SetFlags(log.LstdFlags | log.Lshortfile)
  61. f, err := parse(os.Args)
  62. if err != nil {
  63. os.Exit(2)
  64. }
  65. t := newTester()
  66. k, err := t.getKubetest(f.get, f.old)
  67. if err != nil {
  68. log.Fatalf("err: %v", err)
  69. }
  70. log.Printf("Calling kubetest %v...", strings.Join(f.args, " "))
  71. if err = t.wait(k, f.args...); err != nil {
  72. log.Fatalf("err: %v", err)
  73. }
  74. log.Print("Done")
  75. }
  76. func wait(cmd string, args ...string) error {
  77. sigChannel := make(chan os.Signal, 1)
  78. signal.Notify(sigChannel, os.Interrupt)
  79. c := exec.Command(cmd, args...)
  80. c.Stdout = os.Stdout
  81. c.Stderr = os.Stderr
  82. if err := c.Start(); err != nil {
  83. return err
  84. }
  85. go func() {
  86. sig := <-sigChannel
  87. if err := c.Process.Signal(sig); err != nil {
  88. log.Fatalf("could not send %s signal %s: %v", cmd, sig, err)
  89. }
  90. }()
  91. return c.Wait()
  92. }
  93. // Struct that allows unit tests to override functionality.
  94. type tester struct {
  95. // os.Stat
  96. stat func(string) (os.FileInfo, error)
  97. // exec.LookPath
  98. lookPath func(string) (string, error)
  99. // build.Default.GOPATH
  100. goPath string
  101. wait func(string, ...string) error
  102. }
  103. func newTester() tester {
  104. return tester{os.Stat, exec.LookPath, build.Default.GOPATH, wait}
  105. }
  106. // Try to find kubetest, either GOPATH/bin/kubetest or PATH
  107. func (t tester) lookKubetest() (string, error) {
  108. // Check for kubetest in GOPATH/bin
  109. if t.goPath != "" {
  110. p := filepath.Join(t.goPath, "bin", "kubetest")
  111. _, err := t.stat(p)
  112. if err == nil {
  113. return p, nil
  114. }
  115. }
  116. // Check for kubetest in PATH
  117. p, err := t.lookPath("kubetest")
  118. return p, err
  119. }
  120. // Upgrade if kubetest does not exist or has not been updated today
  121. func (t tester) getKubetest(get bool, old time.Duration) (string, error) {
  122. // Find kubetest installation
  123. p, err := t.lookKubetest()
  124. if err == nil && !get {
  125. return p, nil // Installed, Skip update
  126. }
  127. if err == nil {
  128. // Installed recently?
  129. if s, err := t.stat(p); err != nil {
  130. return p, err // Cannot stat
  131. } else if time.Since(s.ModTime()) <= old {
  132. return p, nil // Recently updated
  133. } else if t.goPath == "" {
  134. log.Print("Skipping kubetest upgrade because $GOPATH is empty")
  135. return p, nil
  136. }
  137. log.Printf("The kubetest binary is older than %s.", old)
  138. }
  139. if t.goPath == "" {
  140. return "", fmt.Errorf("Cannot install kubetest until $GOPATH is set")
  141. }
  142. log.Print("Updating kubetest binary...")
  143. cmd := []string{"go", "get", "-u", "k8s.io/test-infra/kubetest"}
  144. if err = t.wait(cmd[0], cmd[1:]...); err != nil {
  145. return "", fmt.Errorf("%s: %v", strings.Join(cmd, " "), err) // Could not upgrade
  146. }
  147. if p, err = t.lookKubetest(); err != nil {
  148. return "", err // Cannot find kubetest
  149. } else if err = t.wait("touch", p); err != nil {
  150. return "", err // Could not touch
  151. } else {
  152. return p, nil // Updated modtime
  153. }
  154. }