github.com/dmaizel/tests@v0.0.0-20210728163746-cae6a2d9cee8/integration/docker/kill_test.go (about)

     1  // Copyright (c) 2018 Intel Corporation
     2  //
     3  // SPDX-License-Identifier: Apache-2.0
     4  
     5  package docker
     6  
     7  import (
     8  	"fmt"
     9  	"strings"
    10  	"syscall"
    11  	"time"
    12  
    13  	. "github.com/kata-containers/tests"
    14  	. "github.com/onsi/ginkgo"
    15  	. "github.com/onsi/ginkgo/extensions/table"
    16  	. "github.com/onsi/gomega"
    17  )
    18  
    19  const (
    20  	canBeTrapped = true
    21  )
    22  
    23  var genericSignalMap = map[syscall.Signal]bool{
    24  	syscall.SIGHUP:    canBeTrapped,
    25  	syscall.SIGINT:    canBeTrapped,
    26  	syscall.SIGQUIT:   canBeTrapped,
    27  	syscall.SIGILL:    canBeTrapped,
    28  	syscall.SIGTRAP:   canBeTrapped,
    29  	syscall.SIGIOT:    canBeTrapped,
    30  	syscall.SIGFPE:    canBeTrapped,
    31  	syscall.SIGUSR1:   canBeTrapped,
    32  	syscall.SIGSEGV:   canBeTrapped,
    33  	syscall.SIGUSR2:   canBeTrapped,
    34  	syscall.SIGPIPE:   canBeTrapped,
    35  	syscall.SIGALRM:   canBeTrapped,
    36  	syscall.SIGTERM:   canBeTrapped,
    37  	syscall.SIGCHLD:   canBeTrapped,
    38  	syscall.SIGCONT:   canBeTrapped,
    39  	syscall.SIGTSTP:   canBeTrapped,
    40  	syscall.SIGTTIN:   canBeTrapped,
    41  	syscall.SIGTTOU:   canBeTrapped,
    42  	syscall.SIGURG:    canBeTrapped,
    43  	syscall.SIGXCPU:   canBeTrapped,
    44  	syscall.SIGXFSZ:   canBeTrapped,
    45  	syscall.SIGVTALRM: canBeTrapped,
    46  	syscall.SIGPROF:   canBeTrapped,
    47  	syscall.SIGWINCH:  canBeTrapped,
    48  	syscall.SIGIO:     canBeTrapped,
    49  }
    50  
    51  func withoutSignal() TableEntry {
    52  	// Value denoting a command interrupted by a signal (http://www.tldp.org/LDP/abs/html/exitcodes.html)
    53  	const interruptedBySignal = 128
    54  
    55  	expectedExitCode := interruptedBySignal + int(syscall.SIGKILL)
    56  	return Entry("without a signal", syscall.Signal(0), expectedExitCode, true)
    57  }
    58  
    59  func withSignalNotExitCode(signal syscall.Signal) TableEntry {
    60  	return Entry(fmt.Sprintf("with '%d' (%s) signal, don't change the exit code", signal, signal), signal, 0, false)
    61  }
    62  
    63  func withGenericSignals(signalsMap map[syscall.Signal]bool) []TableEntry {
    64  	var table []TableEntry
    65  	var expectedExitCode int
    66  	for signal, trap := range signalsMap {
    67  		expectedExitCode = int(signal)
    68  		if !trap {
    69  			// 128 -> command interrupted by a signal
    70  			// http://www.tldp.org/LDP/abs/html/exitcodes.html
    71  			expectedExitCode += 128
    72  
    73  		}
    74  		table = append(table, Entry(fmt.Sprintf("with '%d'(%s) signal", int(signal), signal), signal, expectedExitCode, true))
    75  	}
    76  	return append(table, withoutSignal(), withSignalNotExitCode(syscall.SIGSTOP))
    77  }
    78  
    79  var _ = Describe("docker kill", func() {
    80  	var (
    81  		args []string
    82  		id   string
    83  	)
    84  
    85  	BeforeEach(func() {
    86  		id = randomDockerName()
    87  	})
    88  
    89  	AfterEach(func() {
    90  		Expect(RemoveDockerContainer(id)).To(BeTrue())
    91  		Expect(ExistDockerContainer(id)).NotTo(BeTrue())
    92  	})
    93  
    94  	DescribeTable("killing container",
    95  		func(signal syscall.Signal, expectedExitCode int, waitForExit bool) {
    96  			args = []string{"--name", id, "-dt", Image, "sh", "-c"}
    97  
    98  			switch signal {
    99  			case syscall.SIGQUIT, syscall.SIGILL, syscall.SIGBUS, syscall.SIGFPE, syscall.SIGSEGV, syscall.SIGPIPE:
   100  				Skip("This is not forwarded by kata-shim " +
   101  					"https://github.com/kata-containers/shim/issues/4")
   102  			case syscall.SIGWINCH:
   103  			}
   104  
   105  			trapTag := "TRAP_RUNNING"
   106  			trapCmd := fmt.Sprintf("trap \"exit %d\" %d; echo %s", signal, signal, trapTag)
   107  			infiniteLoop := "while :; do sleep 1; done"
   108  
   109  			if signal > 0 {
   110  				args = append(args, fmt.Sprintf("%s; %s", trapCmd, infiniteLoop))
   111  			} else {
   112  				args = append(args, infiniteLoop)
   113  			}
   114  
   115  			_, _, runExitCode := dockerRun(args...)
   116  			Expect(runExitCode).To(Equal(0))
   117  
   118  			if signal > 0 {
   119  				exitCh := make(chan bool)
   120  
   121  				go func() {
   122  					for {
   123  						// Don't check for error here since the command
   124  						// can fail if the container is not running yet.
   125  						logs, _ := LogsDockerContainer(id)
   126  						if strings.Contains(logs, trapTag) {
   127  							break
   128  						}
   129  
   130  						time.Sleep(time.Second)
   131  					}
   132  
   133  					close(exitCh)
   134  				}()
   135  
   136  				var err error
   137  
   138  				select {
   139  				case <-exitCh:
   140  					err = nil
   141  				case <-time.After(time.Duration(Timeout) * time.Second):
   142  					err = fmt.Errorf("Timeout reached after %ds", Timeout)
   143  				}
   144  
   145  				Expect(err).ToNot(HaveOccurred())
   146  
   147  				dockerKill("-s", fmt.Sprintf("%d", signal), id)
   148  			} else {
   149  				dockerKill(id)
   150  			}
   151  
   152  			exitCode, err := ExitCodeDockerContainer(id, waitForExit)
   153  			Expect(err).ToNot(HaveOccurred())
   154  			Expect(exitCode).To(Equal(expectedExitCode))
   155  		},
   156  		withOSSignals(genericSignalMap)...,
   157  	)
   158  })