github.com/hhrutter/nomad@v0.6.0-rc2.0.20170723054333-80c4b03f0705/client/driver/exec_unix_test.go (about)

     1  // +build !windows
     2  
     3  package driver
     4  
     5  import (
     6  	"encoding/json"
     7  	"io/ioutil"
     8  	"os"
     9  	"path/filepath"
    10  	"strings"
    11  	"syscall"
    12  	"testing"
    13  	"time"
    14  
    15  	"github.com/hashicorp/nomad/nomad/structs"
    16  	"github.com/hashicorp/nomad/testutil"
    17  
    18  	ctestutils "github.com/hashicorp/nomad/client/testutil"
    19  )
    20  
    21  func TestExecDriver_KillUserPid_OnPluginReconnectFailure(t *testing.T) {
    22  	if !testutil.IsTravis() {
    23  		t.Parallel()
    24  	}
    25  	ctestutils.ExecCompatible(t)
    26  	task := &structs.Task{
    27  		Name:   "sleep",
    28  		Driver: "exec",
    29  		Config: map[string]interface{}{
    30  			"command": "/bin/sleep",
    31  			"args":    []string{"1000000"},
    32  		},
    33  		LogConfig: &structs.LogConfig{
    34  			MaxFiles:      10,
    35  			MaxFileSizeMB: 10,
    36  		},
    37  		Resources: basicResources,
    38  	}
    39  
    40  	ctx := testDriverContexts(t, task)
    41  	defer ctx.AllocDir.Destroy()
    42  	d := NewExecDriver(ctx.DriverCtx)
    43  
    44  	if _, err := d.Prestart(ctx.ExecCtx, task); err != nil {
    45  		t.Fatalf("prestart err: %v", err)
    46  	}
    47  	resp, err := d.Start(ctx.ExecCtx, task)
    48  	if err != nil {
    49  		t.Fatalf("err: %v", err)
    50  	}
    51  	defer resp.Handle.Kill()
    52  
    53  	id := &execId{}
    54  	if err := json.Unmarshal([]byte(resp.Handle.ID()), id); err != nil {
    55  		t.Fatalf("Failed to parse handle '%s': %v", resp.Handle.ID(), err)
    56  	}
    57  	pluginPid := id.PluginConfig.Pid
    58  	proc, err := os.FindProcess(pluginPid)
    59  	if err != nil {
    60  		t.Fatalf("can't find plugin pid: %v", pluginPid)
    61  	}
    62  	if err := proc.Kill(); err != nil {
    63  		t.Fatalf("can't kill plugin pid: %v", err)
    64  	}
    65  
    66  	// Attempt to open
    67  	handle2, err := d.Open(ctx.ExecCtx, resp.Handle.ID())
    68  	if err == nil {
    69  		t.Fatalf("expected error")
    70  	}
    71  	if handle2 != nil {
    72  		handle2.Kill()
    73  		t.Fatalf("expected handle2 to be nil")
    74  	}
    75  
    76  	// Test if the userpid is still present
    77  	userProc, _ := os.FindProcess(id.UserPid)
    78  
    79  	for retry := 3; retry > 0; retry-- {
    80  		if err = userProc.Signal(syscall.Signal(0)); err != nil {
    81  			// Process is gone as expected; exit
    82  			return
    83  		}
    84  
    85  		// Killing processes is async; wait and check again
    86  		time.Sleep(time.Second)
    87  	}
    88  	if err = userProc.Signal(syscall.Signal(0)); err == nil {
    89  		t.Fatalf("expected user process to die")
    90  	}
    91  }
    92  
    93  func TestExecDriver_Signal(t *testing.T) {
    94  	if !testutil.IsTravis() {
    95  		t.Parallel()
    96  	}
    97  	ctestutils.ExecCompatible(t)
    98  	task := &structs.Task{
    99  		Name:   "signal",
   100  		Driver: "exec",
   101  		Config: map[string]interface{}{
   102  			"command": "/bin/bash",
   103  			"args":    []string{"test.sh"},
   104  		},
   105  		LogConfig: &structs.LogConfig{
   106  			MaxFiles:      10,
   107  			MaxFileSizeMB: 10,
   108  		},
   109  		Resources:   basicResources,
   110  		KillTimeout: 10 * time.Second,
   111  	}
   112  
   113  	ctx := testDriverContexts(t, task)
   114  	defer ctx.AllocDir.Destroy()
   115  	d := NewExecDriver(ctx.DriverCtx)
   116  
   117  	testFile := filepath.Join(ctx.ExecCtx.TaskDir.Dir, "test.sh")
   118  	testData := []byte(`
   119  at_term() {
   120      echo 'Terminated.'
   121      exit 3
   122  }
   123  trap at_term USR1
   124  while true; do
   125      sleep 1
   126  done
   127  	`)
   128  	if err := ioutil.WriteFile(testFile, testData, 0777); err != nil {
   129  		t.Fatalf("Failed to write data: %v", err)
   130  	}
   131  
   132  	if _, err := d.Prestart(ctx.ExecCtx, task); err != nil {
   133  		t.Fatalf("prestart err: %v", err)
   134  	}
   135  	resp, err := d.Start(ctx.ExecCtx, task)
   136  	if err != nil {
   137  		t.Fatalf("err: %v", err)
   138  	}
   139  
   140  	go func() {
   141  		time.Sleep(100 * time.Millisecond)
   142  		err := resp.Handle.Signal(syscall.SIGUSR1)
   143  		if err != nil {
   144  			t.Fatalf("err: %v", err)
   145  		}
   146  	}()
   147  
   148  	// Task should terminate quickly
   149  	select {
   150  	case res := <-resp.Handle.WaitCh():
   151  		if res.Successful() {
   152  			t.Fatal("should err")
   153  		}
   154  	case <-time.After(time.Duration(testutil.TestMultiplier()*6) * time.Second):
   155  		t.Fatalf("timeout")
   156  	}
   157  
   158  	// Check the log file to see it exited because of the signal
   159  	outputFile := filepath.Join(ctx.ExecCtx.TaskDir.LogDir, "signal.stdout.0")
   160  	act, err := ioutil.ReadFile(outputFile)
   161  	if err != nil {
   162  		t.Fatalf("Couldn't read expected output: %v", err)
   163  	}
   164  
   165  	exp := "Terminated."
   166  	if strings.TrimSpace(string(act)) != exp {
   167  		t.Logf("Read from %v", outputFile)
   168  		t.Fatalf("Command outputted %v; want %v", act, exp)
   169  	}
   170  }