...

Source file src/k8s.io/kubernetes/test/conformance/image/go-runner/main.go

Documentation: k8s.io/kubernetes/test/conformance/image/go-runner

     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  }
   139  

View as plain text