github.com/blixtra/nomad@v0.7.2-0.20171221000451-da9a1d7bb050/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  	"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  	t.Parallel()
    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  	t.Parallel()
    64  	task := &structs.Task{
    65  		Name:   "sleep",
    66  		Driver: "raw_exec",
    67  		Config: map[string]interface{}{
    68  			"command": testtask.Path(),
    69  			"args":    []string{"sleep", "1s"},
    70  		},
    71  		LogConfig: &structs.LogConfig{
    72  			MaxFiles:      10,
    73  			MaxFileSizeMB: 10,
    74  		},
    75  		Resources: basicResources,
    76  	}
    77  	testtask.SetTaskEnv(task)
    78  	ctx := testDriverContexts(t, task)
    79  	defer ctx.AllocDir.Destroy()
    80  	d := NewRawExecDriver(ctx.DriverCtx)
    81  
    82  	if _, err := d.Prestart(ctx.ExecCtx, task); err != nil {
    83  		t.Fatalf("prestart err: %v", err)
    84  	}
    85  	resp, err := d.Start(ctx.ExecCtx, task)
    86  	if err != nil {
    87  		t.Fatalf("err: %v", err)
    88  	}
    89  
    90  	// Attempt to open
    91  	handle2, err := d.Open(ctx.ExecCtx, resp.Handle.ID())
    92  	if err != nil {
    93  		t.Fatalf("err: %v", err)
    94  	}
    95  	if handle2 == nil {
    96  		t.Fatalf("missing handle")
    97  	}
    98  
    99  	// Task should terminate quickly
   100  	select {
   101  	case <-handle2.WaitCh():
   102  	case <-time.After(time.Duration(testutil.TestMultiplier()*5) * time.Second):
   103  		t.Fatalf("timeout")
   104  	}
   105  	resp.Handle.Kill()
   106  	handle2.Kill()
   107  }
   108  
   109  func TestRawExecDriver_Start_Wait(t *testing.T) {
   110  	t.Parallel()
   111  	task := &structs.Task{
   112  		Name:   "sleep",
   113  		Driver: "raw_exec",
   114  		Config: map[string]interface{}{
   115  			"command": testtask.Path(),
   116  			"args":    []string{"sleep", "1s"},
   117  		},
   118  		LogConfig: &structs.LogConfig{
   119  			MaxFiles:      10,
   120  			MaxFileSizeMB: 10,
   121  		},
   122  		Resources: basicResources,
   123  	}
   124  	testtask.SetTaskEnv(task)
   125  	ctx := testDriverContexts(t, task)
   126  	defer ctx.AllocDir.Destroy()
   127  	d := NewRawExecDriver(ctx.DriverCtx)
   128  
   129  	if _, err := d.Prestart(ctx.ExecCtx, task); err != nil {
   130  		t.Fatalf("prestart err: %v", err)
   131  	}
   132  	resp, err := d.Start(ctx.ExecCtx, task)
   133  	if err != nil {
   134  		t.Fatalf("err: %v", err)
   135  	}
   136  
   137  	// Update should be a no-op
   138  	err = resp.Handle.Update(task)
   139  	if err != nil {
   140  		t.Fatalf("err: %v", err)
   141  	}
   142  
   143  	// Task should terminate quickly
   144  	select {
   145  	case res := <-resp.Handle.WaitCh():
   146  		if !res.Successful() {
   147  			t.Fatalf("err: %v", res)
   148  		}
   149  	case <-time.After(time.Duration(testutil.TestMultiplier()*5) * time.Second):
   150  		t.Fatalf("timeout")
   151  	}
   152  }
   153  
   154  func TestRawExecDriver_Start_Wait_AllocDir(t *testing.T) {
   155  	t.Parallel()
   156  	exp := []byte("win")
   157  	file := "output.txt"
   158  	outPath := fmt.Sprintf(`${%s}/%s`, env.AllocDir, file)
   159  	task := &structs.Task{
   160  		Name:   "sleep",
   161  		Driver: "raw_exec",
   162  		Config: map[string]interface{}{
   163  			"command": testtask.Path(),
   164  			"args": []string{
   165  				"sleep", "1s",
   166  				"write", string(exp), outPath,
   167  			},
   168  		},
   169  		LogConfig: &structs.LogConfig{
   170  			MaxFiles:      10,
   171  			MaxFileSizeMB: 10,
   172  		},
   173  		Resources: basicResources,
   174  	}
   175  	testtask.SetTaskEnv(task)
   176  
   177  	ctx := testDriverContexts(t, task)
   178  	defer ctx.AllocDir.Destroy()
   179  	d := NewRawExecDriver(ctx.DriverCtx)
   180  
   181  	if _, err := d.Prestart(ctx.ExecCtx, task); err != nil {
   182  		t.Fatalf("prestart err: %v", err)
   183  	}
   184  	resp, err := d.Start(ctx.ExecCtx, task)
   185  	if err != nil {
   186  		t.Fatalf("err: %v", err)
   187  	}
   188  
   189  	// Task should terminate quickly
   190  	select {
   191  	case res := <-resp.Handle.WaitCh():
   192  		if !res.Successful() {
   193  			t.Fatalf("err: %v", res)
   194  		}
   195  	case <-time.After(time.Duration(testutil.TestMultiplier()*5) * time.Second):
   196  		t.Fatalf("timeout")
   197  	}
   198  
   199  	// Check that data was written to the shared alloc directory.
   200  	outputFile := filepath.Join(ctx.AllocDir.SharedDir, file)
   201  	act, err := ioutil.ReadFile(outputFile)
   202  	if err != nil {
   203  		t.Fatalf("Couldn't read expected output: %v", err)
   204  	}
   205  
   206  	if !reflect.DeepEqual(act, exp) {
   207  		t.Fatalf("Command outputted %v; want %v", act, exp)
   208  	}
   209  }
   210  
   211  func TestRawExecDriver_Start_Kill_Wait(t *testing.T) {
   212  	t.Parallel()
   213  	task := &structs.Task{
   214  		Name:   "sleep",
   215  		Driver: "raw_exec",
   216  		Config: map[string]interface{}{
   217  			"command": testtask.Path(),
   218  			"args":    []string{"sleep", "45s"},
   219  		},
   220  		LogConfig: &structs.LogConfig{
   221  			MaxFiles:      10,
   222  			MaxFileSizeMB: 10,
   223  		},
   224  		Resources: basicResources,
   225  	}
   226  	testtask.SetTaskEnv(task)
   227  
   228  	ctx := testDriverContexts(t, task)
   229  	defer ctx.AllocDir.Destroy()
   230  	d := NewRawExecDriver(ctx.DriverCtx)
   231  
   232  	if _, err := d.Prestart(ctx.ExecCtx, task); err != nil {
   233  		t.Fatalf("prestart err: %v", err)
   234  	}
   235  	resp, err := d.Start(ctx.ExecCtx, task)
   236  	if err != nil {
   237  		t.Fatalf("err: %v", err)
   238  	}
   239  
   240  	go func() {
   241  		time.Sleep(1 * time.Second)
   242  		err := resp.Handle.Kill()
   243  
   244  		// Can't rely on the ordering between wait and kill on travis...
   245  		if !testutil.IsTravis() && err != nil {
   246  			t.Fatalf("err: %v", err)
   247  		}
   248  	}()
   249  
   250  	// Task should terminate quickly
   251  	select {
   252  	case res := <-resp.Handle.WaitCh():
   253  		if res.Successful() {
   254  			t.Fatal("should err")
   255  		}
   256  	case <-time.After(time.Duration(testutil.TestMultiplier()*5) * time.Second):
   257  		t.Fatalf("timeout")
   258  	}
   259  }
   260  
   261  func TestRawExecDriver_HandlerExec(t *testing.T) {
   262  	t.Parallel()
   263  	task := &structs.Task{
   264  		Name:   "sleep",
   265  		Driver: "raw_exec",
   266  		Config: map[string]interface{}{
   267  			"command": testtask.Path(),
   268  			"args":    []string{"sleep", "9000s"},
   269  		},
   270  		LogConfig: &structs.LogConfig{
   271  			MaxFiles:      10,
   272  			MaxFileSizeMB: 10,
   273  		},
   274  		Resources: basicResources,
   275  	}
   276  	testtask.SetTaskEnv(task)
   277  	ctx := testDriverContexts(t, task)
   278  	defer ctx.AllocDir.Destroy()
   279  	d := NewRawExecDriver(ctx.DriverCtx)
   280  
   281  	if _, err := d.Prestart(ctx.ExecCtx, task); err != nil {
   282  		t.Fatalf("prestart err: %v", err)
   283  	}
   284  	resp, err := d.Start(ctx.ExecCtx, task)
   285  	if err != nil {
   286  		t.Fatalf("err: %v", err)
   287  	}
   288  
   289  	// Exec a command that should work
   290  	out, code, err := resp.Handle.Exec(context.TODO(), "/usr/bin/stat", []string{"/tmp"})
   291  	if err != nil {
   292  		t.Fatalf("error exec'ing stat: %v", err)
   293  	}
   294  	if code != 0 {
   295  		t.Fatalf("expected `stat /alloc` to succeed but exit code was: %d", code)
   296  	}
   297  	if expected := 100; len(out) < expected {
   298  		t.Fatalf("expected at least %d bytes of output but found %d:\n%s", expected, len(out), out)
   299  	}
   300  
   301  	// Exec a command that should fail
   302  	out, code, err = resp.Handle.Exec(context.TODO(), "/usr/bin/stat", []string{"lkjhdsaflkjshowaisxmcvnlia"})
   303  	if err != nil {
   304  		t.Fatalf("error exec'ing stat: %v", err)
   305  	}
   306  	if code == 0 {
   307  		t.Fatalf("expected `stat` to fail but exit code was: %d", code)
   308  	}
   309  	if expected := "No such file or directory"; !bytes.Contains(out, []byte(expected)) {
   310  		t.Fatalf("expected output to contain %q but found: %q", expected, out)
   311  	}
   312  
   313  	select {
   314  	case res := <-resp.Handle.WaitCh():
   315  		t.Fatalf("Shouldn't be exited: %v", res.String())
   316  	default:
   317  	}
   318  
   319  	if err := resp.Handle.Kill(); err != nil {
   320  		t.Fatalf("error killing exec handle: %v", err)
   321  	}
   322  }