github.com/ranjib/nomad@v0.1.1-0.20160225204057-97751b02f70b/client/driver/exec_test.go (about)

     1  package driver
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"os"
     8  	"path/filepath"
     9  	"reflect"
    10  	"syscall"
    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/nomad/structs"
    17  	"github.com/hashicorp/nomad/testutil"
    18  
    19  	ctestutils "github.com/hashicorp/nomad/client/testutil"
    20  )
    21  
    22  func TestExecDriver_Fingerprint(t *testing.T) {
    23  	t.Parallel()
    24  	ctestutils.ExecCompatible(t)
    25  	driverCtx, _ := testDriverContexts(&structs.Task{Name: "foo"})
    26  	d := NewExecDriver(driverCtx)
    27  	node := &structs.Node{
    28  		Attributes: map[string]string{
    29  			"unique.cgroup.mountpoint": "/sys/fs/cgroup",
    30  		},
    31  	}
    32  	apply, err := d.Fingerprint(&config.Config{}, node)
    33  	if err != nil {
    34  		t.Fatalf("err: %v", err)
    35  	}
    36  	if !apply {
    37  		t.Fatalf("should apply")
    38  	}
    39  	if node.Attributes["driver.exec"] == "" {
    40  		t.Fatalf("missing driver")
    41  	}
    42  }
    43  
    44  func TestExecDriver_StartOpen_Wait(t *testing.T) {
    45  	t.Parallel()
    46  	ctestutils.ExecCompatible(t)
    47  	task := &structs.Task{
    48  		Name: "sleep",
    49  		Config: map[string]interface{}{
    50  			"command": "/bin/sleep",
    51  			"args":    []string{"5"},
    52  		},
    53  		LogConfig: &structs.LogConfig{
    54  			MaxFiles:      10,
    55  			MaxFileSizeMB: 10,
    56  		},
    57  		Resources: basicResources,
    58  	}
    59  
    60  	driverCtx, execCtx := testDriverContexts(task)
    61  	defer execCtx.AllocDir.Destroy()
    62  	d := NewExecDriver(driverCtx)
    63  
    64  	handle, err := d.Start(execCtx, task)
    65  	if err != nil {
    66  		t.Fatalf("err: %v", err)
    67  	}
    68  	if handle == nil {
    69  		t.Fatalf("missing handle")
    70  	}
    71  
    72  	// Attempt to open
    73  	handle2, err := d.Open(execCtx, handle.ID())
    74  	if err != nil {
    75  		t.Fatalf("err: %v", err)
    76  	}
    77  	if handle2 == nil {
    78  		t.Fatalf("missing handle")
    79  	}
    80  
    81  	handle.Kill()
    82  	handle2.Kill()
    83  }
    84  
    85  func TestExecDriver_KillUserPid_OnPluginReconnectFailure(t *testing.T) {
    86  	t.Parallel()
    87  	ctestutils.ExecCompatible(t)
    88  	task := &structs.Task{
    89  		Name: "sleep",
    90  		Config: map[string]interface{}{
    91  			"command": "/bin/sleep",
    92  			"args":    []string{"1000000"},
    93  		},
    94  		LogConfig: &structs.LogConfig{
    95  			MaxFiles:      10,
    96  			MaxFileSizeMB: 10,
    97  		},
    98  		Resources: basicResources,
    99  	}
   100  
   101  	driverCtx, execCtx := testDriverContexts(task)
   102  	defer execCtx.AllocDir.Destroy()
   103  	d := NewExecDriver(driverCtx)
   104  
   105  	handle, err := d.Start(execCtx, task)
   106  	if err != nil {
   107  		t.Fatalf("err: %v", err)
   108  	}
   109  	if handle == nil {
   110  		t.Fatalf("missing handle")
   111  	}
   112  	defer handle.Kill()
   113  
   114  	id := &execId{}
   115  	if err := json.Unmarshal([]byte(handle.ID()), id); err != nil {
   116  		t.Fatalf("Failed to parse handle '%s': %v", handle.ID(), err)
   117  	}
   118  	pluginPid := id.PluginConfig.Pid
   119  	proc, err := os.FindProcess(pluginPid)
   120  	if err != nil {
   121  		t.Fatalf("can't find plugin pid: %v", pluginPid)
   122  	}
   123  	if err := proc.Kill(); err != nil {
   124  		t.Fatalf("can't kill plugin pid: %v", err)
   125  	}
   126  
   127  	// Attempt to open
   128  	handle2, err := d.Open(execCtx, handle.ID())
   129  	if err == nil {
   130  		t.Fatalf("expected error")
   131  	}
   132  	if handle2 != nil {
   133  		handle2.Kill()
   134  		t.Fatalf("expected handle2 to be nil")
   135  	}
   136  	// Test if the userpid is still present
   137  	userProc, err := os.FindProcess(id.UserPid)
   138  
   139  	err = userProc.Signal(syscall.Signal(0))
   140  
   141  	if err == nil {
   142  		t.Fatalf("expected user process to die")
   143  	}
   144  }
   145  
   146  func TestExecDriver_Start_Wait(t *testing.T) {
   147  	t.Parallel()
   148  	ctestutils.ExecCompatible(t)
   149  	task := &structs.Task{
   150  		Name: "sleep",
   151  		Config: map[string]interface{}{
   152  			"command": "/bin/sleep",
   153  			"args":    []string{"2"},
   154  		},
   155  		LogConfig: &structs.LogConfig{
   156  			MaxFiles:      10,
   157  			MaxFileSizeMB: 10,
   158  		},
   159  		Resources: basicResources,
   160  	}
   161  
   162  	driverCtx, execCtx := testDriverContexts(task)
   163  	defer execCtx.AllocDir.Destroy()
   164  	d := NewExecDriver(driverCtx)
   165  
   166  	handle, err := d.Start(execCtx, task)
   167  	if err != nil {
   168  		t.Fatalf("err: %v", err)
   169  	}
   170  	if handle == nil {
   171  		t.Fatalf("missing handle")
   172  	}
   173  
   174  	// Update should be a no-op
   175  	err = handle.Update(task)
   176  	if err != nil {
   177  		t.Fatalf("err: %v", err)
   178  	}
   179  
   180  	// Task should terminate quickly
   181  	select {
   182  	case res := <-handle.WaitCh():
   183  		if !res.Successful() {
   184  			t.Fatalf("err: %v", res)
   185  		}
   186  	case <-time.After(time.Duration(testutil.TestMultiplier()*5) * time.Second):
   187  		t.Fatalf("timeout")
   188  	}
   189  }
   190  
   191  func TestExecDriver_Start_Artifact_basic(t *testing.T) {
   192  	t.Parallel()
   193  	ctestutils.ExecCompatible(t)
   194  	file := "hi_linux_amd64"
   195  	checksum := "sha256:6f99b4c5184726e601ecb062500aeb9537862434dfe1898dbe5c68d9f50c179c"
   196  
   197  	task := &structs.Task{
   198  		Name: "sleep",
   199  		Config: map[string]interface{}{
   200  			"artifact_source": fmt.Sprintf("https://dl.dropboxusercontent.com/u/47675/jar_thing/%s?checksum=%s", file, checksum),
   201  			"command":         file,
   202  		},
   203  		LogConfig: &structs.LogConfig{
   204  			MaxFiles:      10,
   205  			MaxFileSizeMB: 10,
   206  		},
   207  		Resources: basicResources,
   208  	}
   209  
   210  	driverCtx, execCtx := testDriverContexts(task)
   211  	defer execCtx.AllocDir.Destroy()
   212  	d := NewExecDriver(driverCtx)
   213  
   214  	handle, err := d.Start(execCtx, task)
   215  	if err != nil {
   216  		t.Fatalf("err: %v", err)
   217  	}
   218  	if handle == nil {
   219  		t.Fatalf("missing handle")
   220  	}
   221  
   222  	// Update should be a no-op
   223  	err = handle.Update(task)
   224  	if err != nil {
   225  		t.Fatalf("err: %v", err)
   226  	}
   227  
   228  	// Task should terminate quickly
   229  	select {
   230  	case res := <-handle.WaitCh():
   231  		if !res.Successful() {
   232  			t.Fatalf("err: %v", res)
   233  		}
   234  	case <-time.After(time.Duration(testutil.TestMultiplier()*5) * time.Second):
   235  		t.Fatalf("timeout")
   236  	}
   237  }
   238  
   239  func TestExecDriver_Start_Wait_AllocDir(t *testing.T) {
   240  	t.Parallel()
   241  	ctestutils.ExecCompatible(t)
   242  
   243  	exp := []byte{'w', 'i', 'n'}
   244  	file := "output.txt"
   245  	task := &structs.Task{
   246  		Name: "sleep",
   247  		Config: map[string]interface{}{
   248  			"command": "/bin/bash",
   249  			"args": []string{
   250  				"-c",
   251  				fmt.Sprintf(`sleep 1; echo -n %s > ${%s}/%s`, string(exp), env.AllocDir, file),
   252  			},
   253  		},
   254  		LogConfig: &structs.LogConfig{
   255  			MaxFiles:      10,
   256  			MaxFileSizeMB: 10,
   257  		},
   258  		Resources: basicResources,
   259  	}
   260  
   261  	driverCtx, execCtx := testDriverContexts(task)
   262  	defer execCtx.AllocDir.Destroy()
   263  	d := NewExecDriver(driverCtx)
   264  
   265  	handle, err := d.Start(execCtx, task)
   266  	if err != nil {
   267  		t.Fatalf("err: %v", err)
   268  	}
   269  	if handle == nil {
   270  		t.Fatalf("missing handle")
   271  	}
   272  
   273  	// Task should terminate quickly
   274  	select {
   275  	case res := <-handle.WaitCh():
   276  		if !res.Successful() {
   277  			t.Fatalf("err: %v", res)
   278  		}
   279  	case <-time.After(time.Duration(testutil.TestMultiplier()*5) * time.Second):
   280  		t.Fatalf("timeout")
   281  	}
   282  
   283  	// Check that data was written to the shared alloc directory.
   284  	outputFile := filepath.Join(execCtx.AllocDir.SharedDir, file)
   285  	act, err := ioutil.ReadFile(outputFile)
   286  	if err != nil {
   287  		t.Fatalf("Couldn't read expected output: %v", err)
   288  	}
   289  
   290  	if !reflect.DeepEqual(act, exp) {
   291  		t.Fatalf("Command outputted %v; want %v", act, exp)
   292  	}
   293  }
   294  
   295  func TestExecDriver_Start_Kill_Wait(t *testing.T) {
   296  	t.Parallel()
   297  	ctestutils.ExecCompatible(t)
   298  	task := &structs.Task{
   299  		Name: "sleep",
   300  		Config: map[string]interface{}{
   301  			"command": "/bin/sleep",
   302  			"args":    []string{"100"},
   303  		},
   304  		LogConfig: &structs.LogConfig{
   305  			MaxFiles:      10,
   306  			MaxFileSizeMB: 10,
   307  		},
   308  		Resources:   basicResources,
   309  		KillTimeout: 10 * time.Second,
   310  	}
   311  
   312  	driverCtx, execCtx := testDriverContexts(task)
   313  	defer execCtx.AllocDir.Destroy()
   314  	d := NewExecDriver(driverCtx)
   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.Kill()
   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()*10) * time.Second):
   339  		t.Fatalf("timeout")
   340  	}
   341  }