github.com/diptanu/nomad@v0.5.7-0.20170516172507-d72e86cbe3d9/client/driver/raw_exec_test.go (about)

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