k8s.io/kubernetes@v1.29.3/test/conformance/image/go-runner/main.go (about) 1 /* 2 Copyright 2019 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 main 18 19 import ( 20 "fmt" 21 "io" 22 "log" 23 "os" 24 "os/signal" 25 "path/filepath" 26 "strings" 27 ) 28 29 func main() { 30 if strings.Contains(os.Args[0], "run_e2e.sh") || strings.Contains(os.Args[0], "gorunner") { 31 log.Print("warn: calling test with e2e.test is deprecated and will be removed in 1.25, please rely on container manifest to invoke executable") 32 } 33 env := envWithDefaults(map[string]string{ 34 resultsDirEnvKey: defaultResultsDir, 35 skipEnvKey: defaultSkip, 36 focusEnvKey: defaultFocus, 37 providerEnvKey: defaultProvider, 38 parallelEnvKey: defaultParallel, 39 ginkgoEnvKey: defaultGinkgoBinary, 40 testBinEnvKey: defaultTestBinary, 41 }) 42 43 if err := configureAndRunWithEnv(env); err != nil { 44 log.Fatal(err) 45 } 46 } 47 48 // configureAndRunWithEnv uses the given environment to configure and then start the test run. 49 // It will handle TERM signals gracefully and kill the test process and will 50 // save the logs/results to the location specified via the RESULTS_DIR environment 51 // variable. 52 func configureAndRunWithEnv(env Getenver) error { 53 // Ensure we save results regardless of other errors. This helps any 54 // consumer who may be polling for the results. 55 resultsDir := env.Getenv(resultsDirEnvKey) 56 defer saveResults(resultsDir) 57 58 // Print the output to stdout and a logfile which will be returned 59 // as part of the results tarball. 60 logFilePath := filepath.Join(resultsDir, logFileName) 61 // ensure the resultsDir actually exists 62 if _, err := os.Stat(resultsDir); os.IsNotExist(err) { 63 log.Printf("The resultsDir %v does not exist, will create it", resultsDir) 64 if mkdirErr := os.Mkdir(resultsDir, 0755); mkdirErr != nil { 65 return fmt.Errorf("failed to create log directory %v: %w", resultsDir, mkdirErr) 66 } 67 } 68 logFile, err := os.Create(logFilePath) 69 if err != nil { 70 return fmt.Errorf("failed to create log file %v: %w", logFilePath, err) 71 } 72 mw := io.MultiWriter(os.Stdout, logFile) 73 cmd := getCmd(env, mw) 74 75 log.Printf("Running command:\n%v\n", cmdInfo(cmd)) 76 err = cmd.Start() 77 if err != nil { 78 return fmt.Errorf("starting command: %w", err) 79 } 80 81 // Handle signals and shutdown process gracefully. 82 go setupSigHandler(cmd.Process.Pid) 83 84 err = cmd.Wait() 85 if err != nil { 86 return fmt.Errorf("running command: %w", err) 87 } 88 89 return nil 90 } 91 92 // setupSigHandler will kill the process identified by the given PID if it 93 // gets a TERM signal. 94 func setupSigHandler(pid int) { 95 c := make(chan os.Signal, 1) 96 signal.Notify(c, os.Interrupt) 97 98 // Block until a signal is received. 99 log.Println("Now listening for interrupts") 100 s := <-c 101 log.Printf("Got signal: %v. Shutting down test process (PID: %v)\n", s, pid) 102 p, err := os.FindProcess(pid) 103 if err != nil { 104 log.Printf("Could not find process %v to shut down.\n", pid) 105 return 106 } 107 if err := p.Signal(s); err != nil { 108 log.Printf("Failed to signal test process to terminate: %v\n", err) 109 return 110 } 111 log.Printf("Signalled process %v to terminate successfully.\n", pid) 112 } 113 114 // saveResults will tar the results directory and write the resulting tarball path 115 // into the donefile. 116 func saveResults(resultsDir string) error { 117 log.Printf("Saving results at %v\n", resultsDir) 118 119 err := tarDir(resultsDir, filepath.Join(resultsDir, resultsTarballName)) 120 if err != nil { 121 return fmt.Errorf("tar directory %v: %w", resultsDir, err) 122 } 123 124 doneFile := filepath.Join(resultsDir, doneFileName) 125 126 resultsTarball := filepath.Join(resultsDir, resultsTarballName) 127 resultsTarball, err = filepath.Abs(resultsTarball) 128 if err != nil { 129 return fmt.Errorf("failed to find absolute path for %v: %w", resultsTarball, err) 130 } 131 132 err = os.WriteFile(doneFile, []byte(resultsTarball), os.FileMode(0777)) 133 if err != nil { 134 return fmt.Errorf("writing donefile: %w", err) 135 } 136 137 return nil 138 }