github.com/maier/nomad@v0.4.1-0.20161110003312-a9e3d0b8549d/client/driver/raw_exec_test.go (about)

     1  package driver
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"path/filepath"
     7  	"reflect"
     8  	"strings"
     9  	"syscall"
    10  	"testing"
    11  	"time"
    12  
    13  	"github.com/hashicorp/nomad/client/config"
    14  	"github.com/hashicorp/nomad/client/driver/env"
    15  	"github.com/hashicorp/nomad/helper/testtask"
    16  	"github.com/hashicorp/nomad/nomad/structs"
    17  	"github.com/hashicorp/nomad/testutil"
    18  )
    19  
    20  func TestRawExecDriver_Fingerprint(t *testing.T) {
    21  	task := &structs.Task{
    22  		Name:      "foo",
    23  		Resources: structs.DefaultResources(),
    24  	}
    25  	driverCtx, execCtx := testDriverContexts(task)
    26  	defer execCtx.AllocDir.Destroy()
    27  	d := NewRawExecDriver(driverCtx)
    28  	node := &structs.Node{
    29  		Attributes: make(map[string]string),
    30  	}
    31  
    32  	// Disable raw exec.
    33  	cfg := &config.Config{Options: map[string]string{rawExecConfigOption: "false"}}
    34  
    35  	apply, err := d.Fingerprint(cfg, node)
    36  	if err != nil {
    37  		t.Fatalf("err: %v", err)
    38  	}
    39  	if apply {
    40  		t.Fatalf("should not apply")
    41  	}
    42  	if node.Attributes["driver.raw_exec"] != "" {
    43  		t.Fatalf("driver incorrectly enabled")
    44  	}
    45  
    46  	// Enable raw exec.
    47  	cfg.Options[rawExecConfigOption] = "true"
    48  	apply, err = d.Fingerprint(cfg, node)
    49  	if err != nil {
    50  		t.Fatalf("err: %v", err)
    51  	}
    52  	if !apply {
    53  		t.Fatalf("should apply")
    54  	}
    55  	if node.Attributes["driver.raw_exec"] != "1" {
    56  		t.Fatalf("driver not enabled")
    57  	}
    58  }
    59  
    60  func TestRawExecDriver_StartOpen_Wait(t *testing.T) {
    61  	task := &structs.Task{
    62  		Name: "sleep",
    63  		Config: map[string]interface{}{
    64  			"command": testtask.Path(),
    65  			"args":    []string{"sleep", "1s"},
    66  		},
    67  		LogConfig: &structs.LogConfig{
    68  			MaxFiles:      10,
    69  			MaxFileSizeMB: 10,
    70  		},
    71  		Resources: basicResources,
    72  	}
    73  	testtask.SetTaskEnv(task)
    74  	driverCtx, execCtx := testDriverContexts(task)
    75  	defer execCtx.AllocDir.Destroy()
    76  	d := NewRawExecDriver(driverCtx)
    77  
    78  	handle, err := d.Start(execCtx, task)
    79  	if err != nil {
    80  		t.Fatalf("err: %v", err)
    81  	}
    82  	if handle == nil {
    83  		t.Fatalf("missing handle")
    84  	}
    85  
    86  	// Attempt to open
    87  	handle2, err := d.Open(execCtx, handle.ID())
    88  	if err != nil {
    89  		t.Fatalf("err: %v", err)
    90  	}
    91  	if handle2 == nil {
    92  		t.Fatalf("missing handle")
    93  	}
    94  
    95  	// Task should terminate quickly
    96  	select {
    97  	case <-handle2.WaitCh():
    98  	case <-time.After(time.Duration(testutil.TestMultiplier()*5) * time.Second):
    99  		t.Fatalf("timeout")
   100  	}
   101  	handle.Kill()
   102  	handle2.Kill()
   103  }
   104  
   105  func TestRawExecDriver_Start_Wait(t *testing.T) {
   106  	task := &structs.Task{
   107  		Name: "sleep",
   108  		Config: map[string]interface{}{
   109  			"command": testtask.Path(),
   110  			"args":    []string{"sleep", "1s"},
   111  		},
   112  		LogConfig: &structs.LogConfig{
   113  			MaxFiles:      10,
   114  			MaxFileSizeMB: 10,
   115  		},
   116  		Resources: basicResources,
   117  	}
   118  	testtask.SetTaskEnv(task)
   119  	driverCtx, execCtx := testDriverContexts(task)
   120  	defer execCtx.AllocDir.Destroy()
   121  	d := NewRawExecDriver(driverCtx)
   122  
   123  	handle, err := d.Start(execCtx, task)
   124  	if err != nil {
   125  		t.Fatalf("err: %v", err)
   126  	}
   127  	if handle == nil {
   128  		t.Fatalf("missing handle")
   129  	}
   130  
   131  	// Update should be a no-op
   132  	err = handle.Update(task)
   133  	if err != nil {
   134  		t.Fatalf("err: %v", err)
   135  	}
   136  
   137  	// Task should terminate quickly
   138  	select {
   139  	case res := <-handle.WaitCh():
   140  		if !res.Successful() {
   141  			t.Fatalf("err: %v", res)
   142  		}
   143  	case <-time.After(time.Duration(testutil.TestMultiplier()*5) * time.Second):
   144  		t.Fatalf("timeout")
   145  	}
   146  }
   147  
   148  func TestRawExecDriver_Start_Wait_AllocDir(t *testing.T) {
   149  	exp := []byte{'w', 'i', 'n'}
   150  	file := "output.txt"
   151  	outPath := fmt.Sprintf(`${%s}/%s`, env.AllocDir, file)
   152  	task := &structs.Task{
   153  		Name: "sleep",
   154  		Config: map[string]interface{}{
   155  			"command": testtask.Path(),
   156  			"args": []string{
   157  				"sleep", "1s",
   158  				"write", string(exp), outPath,
   159  			},
   160  		},
   161  		LogConfig: &structs.LogConfig{
   162  			MaxFiles:      10,
   163  			MaxFileSizeMB: 10,
   164  		},
   165  		Resources: basicResources,
   166  	}
   167  	testtask.SetTaskEnv(task)
   168  
   169  	driverCtx, execCtx := testDriverContexts(task)
   170  	defer execCtx.AllocDir.Destroy()
   171  	d := NewRawExecDriver(driverCtx)
   172  
   173  	handle, err := d.Start(execCtx, task)
   174  	if err != nil {
   175  		t.Fatalf("err: %v", err)
   176  	}
   177  	if handle == nil {
   178  		t.Fatalf("missing handle")
   179  	}
   180  
   181  	// Task should terminate quickly
   182  	select {
   183  	case res := <-handle.WaitCh():
   184  		if !res.Successful() {
   185  			t.Fatalf("err: %v", res)
   186  		}
   187  	case <-time.After(time.Duration(testutil.TestMultiplier()*5) * time.Second):
   188  		t.Fatalf("timeout")
   189  	}
   190  
   191  	// Check that data was written to the shared alloc directory.
   192  	outputFile := filepath.Join(execCtx.AllocDir.SharedDir, file)
   193  	act, err := ioutil.ReadFile(outputFile)
   194  	if err != nil {
   195  		t.Fatalf("Couldn't read expected output: %v", err)
   196  	}
   197  
   198  	if !reflect.DeepEqual(act, exp) {
   199  		t.Fatalf("Command outputted %v; want %v", act, exp)
   200  	}
   201  }
   202  
   203  func TestRawExecDriver_Start_Kill_Wait(t *testing.T) {
   204  	task := &structs.Task{
   205  		Name: "sleep",
   206  		Config: map[string]interface{}{
   207  			"command": testtask.Path(),
   208  			"args":    []string{"sleep", "45s"},
   209  		},
   210  		LogConfig: &structs.LogConfig{
   211  			MaxFiles:      10,
   212  			MaxFileSizeMB: 10,
   213  		},
   214  		Resources: basicResources,
   215  	}
   216  	testtask.SetTaskEnv(task)
   217  
   218  	driverCtx, execCtx := testDriverContexts(task)
   219  	defer execCtx.AllocDir.Destroy()
   220  	d := NewRawExecDriver(driverCtx)
   221  
   222  	handle, err := d.Start(execCtx, task)
   223  	if err != nil {
   224  		t.Fatalf("err: %v", err)
   225  	}
   226  	if handle == nil {
   227  		t.Fatalf("missing handle")
   228  	}
   229  
   230  	go func() {
   231  		time.Sleep(1 * time.Second)
   232  		err := handle.Kill()
   233  
   234  		// Can't rely on the ordering between wait and kill on travis...
   235  		if !testutil.IsTravis() && err != nil {
   236  			t.Fatalf("err: %v", err)
   237  		}
   238  	}()
   239  
   240  	// Task should terminate quickly
   241  	select {
   242  	case res := <-handle.WaitCh():
   243  		if res.Successful() {
   244  			t.Fatal("should err")
   245  		}
   246  	case <-time.After(time.Duration(testutil.TestMultiplier()*5) * time.Second):
   247  		t.Fatalf("timeout")
   248  	}
   249  }
   250  
   251  func TestRawExecDriverUser(t *testing.T) {
   252  	task := &structs.Task{
   253  		Name: "sleep",
   254  		User: "alice",
   255  		Config: map[string]interface{}{
   256  			"command": testtask.Path(),
   257  			"args":    []string{"sleep", "45s"},
   258  		},
   259  		LogConfig: &structs.LogConfig{
   260  			MaxFiles:      10,
   261  			MaxFileSizeMB: 10,
   262  		},
   263  		Resources: basicResources,
   264  	}
   265  	testtask.SetTaskEnv(task)
   266  
   267  	driverCtx, execCtx := testDriverContexts(task)
   268  	defer execCtx.AllocDir.Destroy()
   269  	d := NewRawExecDriver(driverCtx)
   270  
   271  	handle, err := d.Start(execCtx, task)
   272  	if err == nil {
   273  		handle.Kill()
   274  		t.Fatalf("Should've failed")
   275  	}
   276  	msg := "unknown user alice"
   277  	if !strings.Contains(err.Error(), msg) {
   278  		t.Fatalf("Expecting '%v' in '%v'", msg, err)
   279  	}
   280  }
   281  
   282  func TestRawExecDriver_Signal(t *testing.T) {
   283  	task := &structs.Task{
   284  		Name: "signal",
   285  		Config: map[string]interface{}{
   286  			"command": "/bin/bash",
   287  			"args":    []string{"test.sh"},
   288  		},
   289  		LogConfig: &structs.LogConfig{
   290  			MaxFiles:      10,
   291  			MaxFileSizeMB: 10,
   292  		},
   293  		Resources:   basicResources,
   294  		KillTimeout: 10 * time.Second,
   295  	}
   296  
   297  	driverCtx, execCtx := testDriverContexts(task)
   298  	defer execCtx.AllocDir.Destroy()
   299  	d := NewExecDriver(driverCtx)
   300  
   301  	testFile := filepath.Join(execCtx.AllocDir.TaskDirs["signal"], "test.sh")
   302  	testData := []byte(`
   303  at_term() {
   304      echo 'Terminated.'
   305      exit 3
   306  }
   307  trap at_term USR1
   308  while true; do
   309      sleep 1
   310  done
   311  	`)
   312  	if err := ioutil.WriteFile(testFile, testData, 0777); err != nil {
   313  		fmt.Errorf("Failed to write data")
   314  	}
   315  
   316  	handle, err := d.Start(execCtx, task)
   317  	if err != nil {
   318  		t.Fatalf("err: %v", err)
   319  	}
   320  	if handle == nil {
   321  		t.Fatalf("missing handle")
   322  	}
   323  
   324  	go func() {
   325  		time.Sleep(100 * time.Millisecond)
   326  		err := handle.Signal(syscall.SIGUSR1)
   327  		if err != nil {
   328  			t.Fatalf("err: %v", err)
   329  		}
   330  	}()
   331  
   332  	// Task should terminate quickly
   333  	select {
   334  	case res := <-handle.WaitCh():
   335  		if res.Successful() {
   336  			t.Fatal("should err")
   337  		}
   338  	case <-time.After(time.Duration(testutil.TestMultiplier()*6) * time.Second):
   339  		t.Fatalf("timeout")
   340  	}
   341  
   342  	// Check the log file to see it exited because of the signal
   343  	outputFile := filepath.Join(execCtx.AllocDir.LogDir(), "signal.stdout.0")
   344  	act, err := ioutil.ReadFile(outputFile)
   345  	if err != nil {
   346  		t.Fatalf("Couldn't read expected output: %v", err)
   347  	}
   348  
   349  	exp := "Terminated."
   350  	if strings.TrimSpace(string(act)) != exp {
   351  		t.Logf("Read from %v", outputFile)
   352  		t.Fatalf("Command outputted %v; want %v", act, exp)
   353  	}
   354  }