github.com/emate/nomad@v0.8.2-wo-binpacking/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  	cstructs "github.com/hashicorp/nomad/client/structs"
    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  	t.Parallel()
    23  	task := &structs.Task{
    24  		Name:      "foo",
    25  		Driver:    "raw_exec",
    26  		Resources: structs.DefaultResources(),
    27  	}
    28  	ctx := testDriverContexts(t, task)
    29  	defer ctx.AllocDir.Destroy()
    30  	d := NewRawExecDriver(ctx.DriverCtx)
    31  	node := &structs.Node{
    32  		Attributes: make(map[string]string),
    33  	}
    34  
    35  	// Disable raw exec.
    36  	cfg := &config.Config{Options: map[string]string{rawExecConfigOption: "false"}}
    37  
    38  	request := &cstructs.FingerprintRequest{Config: cfg, Node: node}
    39  	var response cstructs.FingerprintResponse
    40  	err := d.Fingerprint(request, &response)
    41  	if err != nil {
    42  		t.Fatalf("err: %v", err)
    43  	}
    44  
    45  	if response.Attributes["driver.raw_exec"] != "" {
    46  		t.Fatalf("driver incorrectly enabled")
    47  	}
    48  
    49  	// Enable raw exec.
    50  	request.Config.Options[rawExecConfigOption] = "true"
    51  	err = d.Fingerprint(request, &response)
    52  	if err != nil {
    53  		t.Fatalf("err: %v", err)
    54  	}
    55  
    56  	if !response.Detected {
    57  		t.Fatalf("expected response to be applicable")
    58  	}
    59  
    60  	if response.Attributes["driver.raw_exec"] != "1" {
    61  		t.Fatalf("driver not enabled")
    62  	}
    63  }
    64  
    65  func TestRawExecDriver_StartOpen_Wait(t *testing.T) {
    66  	t.Parallel()
    67  	task := &structs.Task{
    68  		Name:   "sleep",
    69  		Driver: "raw_exec",
    70  		Config: map[string]interface{}{
    71  			"command": testtask.Path(),
    72  			"args":    []string{"sleep", "1s"},
    73  		},
    74  		LogConfig: &structs.LogConfig{
    75  			MaxFiles:      10,
    76  			MaxFileSizeMB: 10,
    77  		},
    78  		Resources: basicResources,
    79  	}
    80  	testtask.SetTaskEnv(task)
    81  	ctx := testDriverContexts(t, task)
    82  	defer ctx.AllocDir.Destroy()
    83  	d := NewRawExecDriver(ctx.DriverCtx)
    84  
    85  	if _, err := d.Prestart(ctx.ExecCtx, task); err != nil {
    86  		t.Fatalf("prestart err: %v", err)
    87  	}
    88  	resp, err := d.Start(ctx.ExecCtx, task)
    89  	if err != nil {
    90  		t.Fatalf("err: %v", err)
    91  	}
    92  
    93  	// Attempt to open
    94  	handle2, err := d.Open(ctx.ExecCtx, resp.Handle.ID())
    95  	if err != nil {
    96  		t.Fatalf("err: %v", err)
    97  	}
    98  	if handle2 == nil {
    99  		t.Fatalf("missing handle")
   100  	}
   101  
   102  	// Task should terminate quickly
   103  	select {
   104  	case <-handle2.WaitCh():
   105  	case <-time.After(time.Duration(testutil.TestMultiplier()*5) * time.Second):
   106  		t.Fatalf("timeout")
   107  	}
   108  	resp.Handle.Kill()
   109  	handle2.Kill()
   110  }
   111  
   112  func TestRawExecDriver_Start_Wait(t *testing.T) {
   113  	t.Parallel()
   114  	task := &structs.Task{
   115  		Name:   "sleep",
   116  		Driver: "raw_exec",
   117  		Config: map[string]interface{}{
   118  			"command": testtask.Path(),
   119  			"args":    []string{"sleep", "1s"},
   120  		},
   121  		LogConfig: &structs.LogConfig{
   122  			MaxFiles:      10,
   123  			MaxFileSizeMB: 10,
   124  		},
   125  		Resources: basicResources,
   126  	}
   127  	testtask.SetTaskEnv(task)
   128  	ctx := testDriverContexts(t, task)
   129  	defer ctx.AllocDir.Destroy()
   130  	d := NewRawExecDriver(ctx.DriverCtx)
   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  	// Update should be a no-op
   141  	err = resp.Handle.Update(task)
   142  	if err != nil {
   143  		t.Fatalf("err: %v", err)
   144  	}
   145  
   146  	// Task should terminate quickly
   147  	select {
   148  	case res := <-resp.Handle.WaitCh():
   149  		if !res.Successful() {
   150  			t.Fatalf("err: %v", res)
   151  		}
   152  	case <-time.After(time.Duration(testutil.TestMultiplier()*5) * time.Second):
   153  		t.Fatalf("timeout")
   154  	}
   155  }
   156  
   157  func TestRawExecDriver_Start_Wait_AllocDir(t *testing.T) {
   158  	t.Parallel()
   159  	exp := []byte("win")
   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  	resp, err := d.Start(ctx.ExecCtx, task)
   188  	if err != nil {
   189  		t.Fatalf("err: %v", err)
   190  	}
   191  
   192  	// Task should terminate quickly
   193  	select {
   194  	case res := <-resp.Handle.WaitCh():
   195  		if !res.Successful() {
   196  			t.Fatalf("err: %v", res)
   197  		}
   198  	case <-time.After(time.Duration(testutil.TestMultiplier()*5) * time.Second):
   199  		t.Fatalf("timeout")
   200  	}
   201  
   202  	// Check that data was written to the shared alloc directory.
   203  	outputFile := filepath.Join(ctx.AllocDir.SharedDir, file)
   204  	act, err := ioutil.ReadFile(outputFile)
   205  	if err != nil {
   206  		t.Fatalf("Couldn't read expected output: %v", err)
   207  	}
   208  
   209  	if !reflect.DeepEqual(act, exp) {
   210  		t.Fatalf("Command outputted %v; want %v", act, exp)
   211  	}
   212  }
   213  
   214  func TestRawExecDriver_Start_Kill_Wait(t *testing.T) {
   215  	t.Parallel()
   216  	task := &structs.Task{
   217  		Name:   "sleep",
   218  		Driver: "raw_exec",
   219  		Config: map[string]interface{}{
   220  			"command": testtask.Path(),
   221  			"args":    []string{"sleep", "45s"},
   222  		},
   223  		LogConfig: &structs.LogConfig{
   224  			MaxFiles:      10,
   225  			MaxFileSizeMB: 10,
   226  		},
   227  		Resources: basicResources,
   228  	}
   229  	testtask.SetTaskEnv(task)
   230  
   231  	ctx := testDriverContexts(t, task)
   232  	defer ctx.AllocDir.Destroy()
   233  	d := NewRawExecDriver(ctx.DriverCtx)
   234  
   235  	if _, err := d.Prestart(ctx.ExecCtx, task); err != nil {
   236  		t.Fatalf("prestart err: %v", err)
   237  	}
   238  	resp, err := d.Start(ctx.ExecCtx, task)
   239  	if err != nil {
   240  		t.Fatalf("err: %v", err)
   241  	}
   242  
   243  	go func() {
   244  		time.Sleep(1 * time.Second)
   245  		err := resp.Handle.Kill()
   246  
   247  		// Can't rely on the ordering between wait and kill on travis...
   248  		if !testutil.IsTravis() && err != nil {
   249  			t.Fatalf("err: %v", err)
   250  		}
   251  	}()
   252  
   253  	// Task should terminate quickly
   254  	select {
   255  	case res := <-resp.Handle.WaitCh():
   256  		if res.Successful() {
   257  			t.Fatal("should err")
   258  		}
   259  	case <-time.After(time.Duration(testutil.TestMultiplier()*5) * time.Second):
   260  		t.Fatalf("timeout")
   261  	}
   262  }
   263  
   264  func TestRawExecDriver_HandlerExec(t *testing.T) {
   265  	t.Parallel()
   266  	task := &structs.Task{
   267  		Name:   "sleep",
   268  		Driver: "raw_exec",
   269  		Config: map[string]interface{}{
   270  			"command": testtask.Path(),
   271  			"args":    []string{"sleep", "9000s"},
   272  		},
   273  		LogConfig: &structs.LogConfig{
   274  			MaxFiles:      10,
   275  			MaxFileSizeMB: 10,
   276  		},
   277  		Resources: basicResources,
   278  	}
   279  	testtask.SetTaskEnv(task)
   280  	ctx := testDriverContexts(t, task)
   281  	defer ctx.AllocDir.Destroy()
   282  	d := NewRawExecDriver(ctx.DriverCtx)
   283  
   284  	if _, err := d.Prestart(ctx.ExecCtx, task); err != nil {
   285  		t.Fatalf("prestart err: %v", err)
   286  	}
   287  	resp, err := d.Start(ctx.ExecCtx, task)
   288  	if err != nil {
   289  		t.Fatalf("err: %v", err)
   290  	}
   291  
   292  	// Exec a command that should work
   293  	out, code, err := resp.Handle.Exec(context.TODO(), "/usr/bin/stat", []string{"/tmp"})
   294  	if err != nil {
   295  		t.Fatalf("error exec'ing stat: %v", err)
   296  	}
   297  	if code != 0 {
   298  		t.Fatalf("expected `stat /alloc` to succeed but exit code was: %d", code)
   299  	}
   300  	if expected := 100; len(out) < expected {
   301  		t.Fatalf("expected at least %d bytes of output but found %d:\n%s", expected, len(out), out)
   302  	}
   303  
   304  	// Exec a command that should fail
   305  	out, code, err = resp.Handle.Exec(context.TODO(), "/usr/bin/stat", []string{"lkjhdsaflkjshowaisxmcvnlia"})
   306  	if err != nil {
   307  		t.Fatalf("error exec'ing stat: %v", err)
   308  	}
   309  	if code == 0 {
   310  		t.Fatalf("expected `stat` to fail but exit code was: %d", code)
   311  	}
   312  	if expected := "No such file or directory"; !bytes.Contains(out, []byte(expected)) {
   313  		t.Fatalf("expected output to contain %q but found: %q", expected, out)
   314  	}
   315  
   316  	select {
   317  	case res := <-resp.Handle.WaitCh():
   318  		t.Fatalf("Shouldn't be exited: %v", res.String())
   319  	default:
   320  	}
   321  
   322  	if err := resp.Handle.Kill(); err != nil {
   323  		t.Fatalf("error killing exec handle: %v", err)
   324  	}
   325  }