github.com/ncodes/nomad@v0.5.7-0.20170403112158-97adf4a74fb3/client/task_runner_test.go (about)

     1  package client
     2  
     3  import (
     4  	"fmt"
     5  	"io/ioutil"
     6  	"log"
     7  	"net/http"
     8  	"net/http/httptest"
     9  	"os"
    10  	"path/filepath"
    11  	"reflect"
    12  	"syscall"
    13  	"testing"
    14  	"time"
    15  
    16  	"github.com/golang/snappy"
    17  	"github.com/ncodes/nomad/client/allocdir"
    18  	"github.com/ncodes/nomad/client/config"
    19  	cstructs "github.com/ncodes/nomad/client/structs"
    20  	"github.com/ncodes/nomad/client/vaultclient"
    21  	"github.com/ncodes/nomad/nomad/mock"
    22  	"github.com/ncodes/nomad/nomad/structs"
    23  	"github.com/ncodes/nomad/testutil"
    24  
    25  	ctestutil "github.com/ncodes/nomad/client/testutil"
    26  )
    27  
    28  func testLogger() *log.Logger {
    29  	return prefixedTestLogger("")
    30  }
    31  
    32  func prefixedTestLogger(prefix string) *log.Logger {
    33  	return log.New(os.Stderr, prefix, log.LstdFlags)
    34  }
    35  
    36  type MockTaskStateUpdater struct {
    37  	state  string
    38  	failed bool
    39  	events []*structs.TaskEvent
    40  }
    41  
    42  func (m *MockTaskStateUpdater) Update(name, state string, event *structs.TaskEvent) {
    43  	if state != "" {
    44  		m.state = state
    45  	}
    46  	if event != nil {
    47  		if event.FailsTask {
    48  			m.failed = true
    49  		}
    50  		m.events = append(m.events, event)
    51  	}
    52  }
    53  
    54  type taskRunnerTestCtx struct {
    55  	upd      *MockTaskStateUpdater
    56  	tr       *TaskRunner
    57  	allocDir *allocdir.AllocDir
    58  }
    59  
    60  // Cleanup calls Destroy on the task runner and alloc dir
    61  func (ctx *taskRunnerTestCtx) Cleanup() {
    62  	ctx.tr.Destroy(structs.NewTaskEvent(structs.TaskKilled))
    63  	ctx.allocDir.Destroy()
    64  }
    65  
    66  func testTaskRunner(t *testing.T, restarts bool) *taskRunnerTestCtx {
    67  	return testTaskRunnerFromAlloc(t, restarts, mock.Alloc())
    68  }
    69  
    70  // Creates a mock task runner using the first task in the first task group of
    71  // the passed allocation.
    72  //
    73  // Callers should defer Cleanup() to cleanup after completion
    74  func testTaskRunnerFromAlloc(t *testing.T, restarts bool, alloc *structs.Allocation) *taskRunnerTestCtx {
    75  	logger := testLogger()
    76  	conf := config.DefaultConfig()
    77  	conf.StateDir = os.TempDir()
    78  	conf.AllocDir = os.TempDir()
    79  	upd := &MockTaskStateUpdater{}
    80  	task := alloc.Job.TaskGroups[0].Tasks[0]
    81  	// Initialize the port listing. This should be done by the offer process but
    82  	// we have a mock so that doesn't happen.
    83  	task.Resources.Networks[0].ReservedPorts = []structs.Port{{Label: "", Value: 80}}
    84  
    85  	allocDir := allocdir.NewAllocDir(testLogger(), filepath.Join(conf.AllocDir, alloc.ID))
    86  	if err := allocDir.Build(); err != nil {
    87  		t.Fatalf("error building alloc dir: %v", err)
    88  		return nil
    89  	}
    90  
    91  	//HACK to get FSIsolation and chroot without using AllocRunner,
    92  	//     TaskRunner, or Drivers
    93  	fsi := cstructs.FSIsolationImage
    94  	switch task.Driver {
    95  	case "raw_exec":
    96  		fsi = cstructs.FSIsolationNone
    97  	case "exec", "java":
    98  		fsi = cstructs.FSIsolationChroot
    99  	}
   100  	taskDir := allocDir.NewTaskDir(task.Name)
   101  	if err := taskDir.Build(false, config.DefaultChrootEnv, fsi); err != nil {
   102  		t.Fatalf("error building task dir %q: %v", task.Name, err)
   103  		return nil
   104  	}
   105  
   106  	vclient := vaultclient.NewMockVaultClient()
   107  	tr := NewTaskRunner(logger, conf, upd.Update, taskDir, alloc, task, vclient)
   108  	if !restarts {
   109  		tr.restartTracker = noRestartsTracker()
   110  	}
   111  	return &taskRunnerTestCtx{upd, tr, allocDir}
   112  }
   113  
   114  // testWaitForTaskToStart waits for the task to or fails the test
   115  func testWaitForTaskToStart(t *testing.T, ctx *taskRunnerTestCtx) {
   116  	// Wait for the task to start
   117  	testutil.WaitForResult(func() (bool, error) {
   118  		l := len(ctx.upd.events)
   119  		if l < 2 {
   120  			return false, fmt.Errorf("Expect two events; got %v", l)
   121  		}
   122  
   123  		if ctx.upd.events[0].Type != structs.TaskReceived {
   124  			return false, fmt.Errorf("First Event was %v; want %v", ctx.upd.events[0].Type, structs.TaskReceived)
   125  		}
   126  
   127  		if l >= 3 {
   128  			if ctx.upd.events[1].Type != structs.TaskSetup {
   129  				return false, fmt.Errorf("Second Event was %v; want %v", ctx.upd.events[1].Type, structs.TaskSetup)
   130  			}
   131  			if ctx.upd.events[2].Type != structs.TaskStarted {
   132  				return false, fmt.Errorf("Third Event was %v; want %v", ctx.upd.events[2].Type, structs.TaskStarted)
   133  			}
   134  		} else {
   135  			if ctx.upd.events[1].Type != structs.TaskStarted {
   136  				return false, fmt.Errorf("Second Event was %v; want %v", ctx.upd.events[1].Type, structs.TaskStarted)
   137  			}
   138  		}
   139  
   140  		return true, nil
   141  	}, func(err error) {
   142  		t.Fatalf("err: %v", err)
   143  	})
   144  }
   145  
   146  func TestTaskRunner_SimpleRun(t *testing.T) {
   147  	ctestutil.ExecCompatible(t)
   148  	ctx := testTaskRunner(t, false)
   149  	ctx.tr.MarkReceived()
   150  	go ctx.tr.Run()
   151  	defer ctx.Cleanup()
   152  
   153  	select {
   154  	case <-ctx.tr.WaitCh():
   155  	case <-time.After(time.Duration(testutil.TestMultiplier()*15) * time.Second):
   156  		t.Fatalf("timeout")
   157  	}
   158  
   159  	if len(ctx.upd.events) != 4 {
   160  		t.Fatalf("should have 3 ctx.updates: %#v", ctx.upd.events)
   161  	}
   162  
   163  	if ctx.upd.state != structs.TaskStateDead {
   164  		t.Fatalf("TaskState %v; want %v", ctx.upd.state, structs.TaskStateDead)
   165  	}
   166  
   167  	if ctx.upd.events[0].Type != structs.TaskReceived {
   168  		t.Fatalf("First Event was %v; want %v", ctx.upd.events[0].Type, structs.TaskReceived)
   169  	}
   170  
   171  	if ctx.upd.events[1].Type != structs.TaskSetup {
   172  		t.Fatalf("Second Event was %v; want %v", ctx.upd.events[1].Type, structs.TaskSetup)
   173  	}
   174  
   175  	if ctx.upd.events[2].Type != structs.TaskStarted {
   176  		t.Fatalf("Second Event was %v; want %v", ctx.upd.events[2].Type, structs.TaskStarted)
   177  	}
   178  
   179  	if ctx.upd.events[3].Type != structs.TaskTerminated {
   180  		t.Fatalf("Third Event was %v; want %v", ctx.upd.events[3].Type, structs.TaskTerminated)
   181  	}
   182  }
   183  
   184  func TestTaskRunner_Run_RecoverableStartError(t *testing.T) {
   185  	alloc := mock.Alloc()
   186  	task := alloc.Job.TaskGroups[0].Tasks[0]
   187  	task.Driver = "mock_driver"
   188  	task.Config = map[string]interface{}{
   189  		"exit_code":               0,
   190  		"start_error":             "driver failure",
   191  		"start_error_recoverable": true,
   192  	}
   193  
   194  	ctx := testTaskRunnerFromAlloc(t, true, alloc)
   195  	ctx.tr.MarkReceived()
   196  	go ctx.tr.Run()
   197  	defer ctx.Cleanup()
   198  
   199  	testutil.WaitForResult(func() (bool, error) {
   200  		if l := len(ctx.upd.events); l < 4 {
   201  			return false, fmt.Errorf("Expect at least four events; got %v", l)
   202  		}
   203  
   204  		if ctx.upd.events[0].Type != structs.TaskReceived {
   205  			return false, fmt.Errorf("First Event was %v; want %v", ctx.upd.events[0].Type, structs.TaskReceived)
   206  		}
   207  
   208  		if ctx.upd.events[1].Type != structs.TaskSetup {
   209  			return false, fmt.Errorf("Second Event was %v; want %v", ctx.upd.events[1].Type, structs.TaskSetup)
   210  		}
   211  
   212  		if ctx.upd.events[2].Type != structs.TaskDriverFailure {
   213  			return false, fmt.Errorf("Third Event was %v; want %v", ctx.upd.events[2].Type, structs.TaskDriverFailure)
   214  		}
   215  
   216  		if ctx.upd.events[3].Type != structs.TaskRestarting {
   217  			return false, fmt.Errorf("Fourth Event was %v; want %v", ctx.upd.events[3].Type, structs.TaskRestarting)
   218  		}
   219  
   220  		return true, nil
   221  	}, func(err error) {
   222  		t.Fatalf("err: %v", err)
   223  	})
   224  }
   225  
   226  func TestTaskRunner_Destroy(t *testing.T) {
   227  	ctestutil.ExecCompatible(t)
   228  	ctx := testTaskRunner(t, true)
   229  	ctx.tr.MarkReceived()
   230  	//FIXME This didn't used to send a kill status update!!!???
   231  	defer ctx.Cleanup()
   232  
   233  	// Change command to ensure we run for a bit
   234  	ctx.tr.task.Config["command"] = "/bin/sleep"
   235  	ctx.tr.task.Config["args"] = []string{"1000"}
   236  	go ctx.tr.Run()
   237  
   238  	// Wait for the task to start
   239  	testWaitForTaskToStart(t, ctx)
   240  
   241  	// Make sure we are collecting a few stats
   242  	time.Sleep(2 * time.Second)
   243  	stats := ctx.tr.LatestResourceUsage()
   244  	if len(stats.Pids) == 0 || stats.ResourceUsage == nil || stats.ResourceUsage.MemoryStats.RSS == 0 {
   245  		t.Fatalf("expected task runner to have some stats")
   246  	}
   247  
   248  	// Begin the tear down
   249  	ctx.tr.Destroy(structs.NewTaskEvent(structs.TaskKilled))
   250  
   251  	select {
   252  	case <-ctx.tr.WaitCh():
   253  	case <-time.After(time.Duration(testutil.TestMultiplier()*15) * time.Second):
   254  		t.Fatalf("timeout")
   255  	}
   256  
   257  	if len(ctx.upd.events) != 5 {
   258  		t.Fatalf("should have 5 ctx.updates: %#v", ctx.upd.events)
   259  	}
   260  
   261  	if ctx.upd.state != structs.TaskStateDead {
   262  		t.Fatalf("TaskState %v; want %v", ctx.upd.state, structs.TaskStateDead)
   263  	}
   264  
   265  	if ctx.upd.events[3].Type != structs.TaskKilling {
   266  		t.Fatalf("Third Event was %v; want %v", ctx.upd.events[3].Type, structs.TaskKilling)
   267  	}
   268  
   269  	if ctx.upd.events[4].Type != structs.TaskKilled {
   270  		t.Fatalf("Third Event was %v; want %v", ctx.upd.events[4].Type, structs.TaskKilled)
   271  	}
   272  }
   273  
   274  func TestTaskRunner_Update(t *testing.T) {
   275  	ctestutil.ExecCompatible(t)
   276  	ctx := testTaskRunner(t, false)
   277  
   278  	// Change command to ensure we run for a bit
   279  	ctx.tr.task.Config["command"] = "/bin/sleep"
   280  	ctx.tr.task.Config["args"] = []string{"100"}
   281  	go ctx.tr.Run()
   282  	defer ctx.Cleanup()
   283  
   284  	// Update the task definition
   285  	updateAlloc := ctx.tr.alloc.Copy()
   286  
   287  	// Update the restart policy
   288  	newTG := updateAlloc.Job.TaskGroups[0]
   289  	newMode := "foo"
   290  	newTG.RestartPolicy.Mode = newMode
   291  
   292  	newTask := updateAlloc.Job.TaskGroups[0].Tasks[0]
   293  	newTask.Driver = "foobar"
   294  
   295  	// Update the kill timeout
   296  	testutil.WaitForResult(func() (bool, error) {
   297  		if ctx.tr.handle == nil {
   298  			return false, fmt.Errorf("task not started")
   299  		}
   300  		return true, nil
   301  	}, func(err error) {
   302  		t.Fatalf("err: %v", err)
   303  	})
   304  
   305  	oldHandle := ctx.tr.handle.ID()
   306  	newTask.KillTimeout = time.Hour
   307  
   308  	ctx.tr.Update(updateAlloc)
   309  
   310  	// Wait for ctx.update to take place
   311  	testutil.WaitForResult(func() (bool, error) {
   312  		if ctx.tr.task == newTask {
   313  			return false, fmt.Errorf("We copied the pointer! This would be very bad")
   314  		}
   315  		if ctx.tr.task.Driver != newTask.Driver {
   316  			return false, fmt.Errorf("Task not copied")
   317  		}
   318  		if ctx.tr.restartTracker.policy.Mode != newMode {
   319  			return false, fmt.Errorf("restart policy not ctx.updated")
   320  		}
   321  		if ctx.tr.handle.ID() == oldHandle {
   322  			return false, fmt.Errorf("handle not ctx.updated")
   323  		}
   324  		return true, nil
   325  	}, func(err error) {
   326  		t.Fatalf("err: %v", err)
   327  	})
   328  }
   329  
   330  func TestTaskRunner_SaveRestoreState(t *testing.T) {
   331  	alloc := mock.Alloc()
   332  	task := alloc.Job.TaskGroups[0].Tasks[0]
   333  	task.Driver = "mock_driver"
   334  	task.Config = map[string]interface{}{
   335  		"exit_code": "0",
   336  		"run_for":   "5s",
   337  	}
   338  
   339  	// Give it a Vault token
   340  	task.Vault = &structs.Vault{Policies: []string{"default"}}
   341  
   342  	ctx := testTaskRunnerFromAlloc(t, false, alloc)
   343  	ctx.tr.MarkReceived()
   344  	go ctx.tr.Run()
   345  	//FIXME This test didn't used to defer destroy the allocidr ???!!!
   346  	defer ctx.Cleanup()
   347  
   348  	// Wait for the task to be running and then snapshot the state
   349  	testWaitForTaskToStart(t, ctx)
   350  
   351  	if err := ctx.tr.SaveState(); err != nil {
   352  		t.Fatalf("err: %v", err)
   353  	}
   354  
   355  	// Read the token from the file system
   356  	tokenPath := filepath.Join(ctx.tr.taskDir.SecretsDir, vaultTokenFile)
   357  	data, err := ioutil.ReadFile(tokenPath)
   358  	if err != nil {
   359  		t.Fatalf("Failed to read file: %v", err)
   360  	}
   361  	token := string(data)
   362  	if len(token) == 0 {
   363  		t.Fatalf("Token not written to disk")
   364  	}
   365  
   366  	// Create a new task runner
   367  	task2 := &structs.Task{Name: ctx.tr.task.Name, Driver: ctx.tr.task.Driver}
   368  	tr2 := NewTaskRunner(ctx.tr.logger, ctx.tr.config, ctx.upd.Update,
   369  		ctx.tr.taskDir, ctx.tr.alloc, task2, ctx.tr.vaultClient)
   370  	tr2.restartTracker = noRestartsTracker()
   371  	if err := tr2.RestoreState(); err != nil {
   372  		t.Fatalf("err: %v", err)
   373  	}
   374  	go tr2.Run()
   375  	defer tr2.Destroy(structs.NewTaskEvent(structs.TaskKilled))
   376  
   377  	// Destroy and wait
   378  	select {
   379  	case <-tr2.WaitCh():
   380  	case <-time.After(time.Duration(testutil.TestMultiplier()*15) * time.Second):
   381  		t.Fatalf("timeout")
   382  	}
   383  
   384  	// Check that we recovered the token
   385  	if act := tr2.vaultFuture.Get(); act != token {
   386  		t.Fatalf("Vault token not properly recovered")
   387  	}
   388  }
   389  
   390  func TestTaskRunner_Download_List(t *testing.T) {
   391  	ctestutil.ExecCompatible(t)
   392  
   393  	ts := httptest.NewServer(http.FileServer(http.Dir(filepath.Dir("."))))
   394  	defer ts.Close()
   395  
   396  	// Create an allocation that has a task with a list of artifacts.
   397  	alloc := mock.Alloc()
   398  	task := alloc.Job.TaskGroups[0].Tasks[0]
   399  	f1 := "task_runner_test.go"
   400  	f2 := "task_runner.go"
   401  	artifact1 := structs.TaskArtifact{
   402  		GetterSource: fmt.Sprintf("%s/%s", ts.URL, f1),
   403  	}
   404  	artifact2 := structs.TaskArtifact{
   405  		GetterSource: fmt.Sprintf("%s/%s", ts.URL, f2),
   406  	}
   407  	task.Artifacts = []*structs.TaskArtifact{&artifact1, &artifact2}
   408  
   409  	ctx := testTaskRunnerFromAlloc(t, false, alloc)
   410  	ctx.tr.MarkReceived()
   411  	go ctx.tr.Run()
   412  	defer ctx.Cleanup()
   413  
   414  	select {
   415  	case <-ctx.tr.WaitCh():
   416  	case <-time.After(time.Duration(testutil.TestMultiplier()*15) * time.Second):
   417  		t.Fatalf("timeout")
   418  	}
   419  
   420  	if len(ctx.upd.events) != 5 {
   421  		t.Fatalf("should have 5 ctx.updates: %#v", ctx.upd.events)
   422  	}
   423  
   424  	if ctx.upd.state != structs.TaskStateDead {
   425  		t.Fatalf("TaskState %v; want %v", ctx.upd.state, structs.TaskStateDead)
   426  	}
   427  
   428  	if ctx.upd.events[0].Type != structs.TaskReceived {
   429  		t.Fatalf("First Event was %v; want %v", ctx.upd.events[0].Type, structs.TaskReceived)
   430  	}
   431  
   432  	if ctx.upd.events[1].Type != structs.TaskSetup {
   433  		t.Fatalf("Second Event was %v; want %v", ctx.upd.events[1].Type, structs.TaskSetup)
   434  	}
   435  
   436  	if ctx.upd.events[2].Type != structs.TaskDownloadingArtifacts {
   437  		t.Fatalf("Third Event was %v; want %v", ctx.upd.events[2].Type, structs.TaskDownloadingArtifacts)
   438  	}
   439  
   440  	if ctx.upd.events[3].Type != structs.TaskStarted {
   441  		t.Fatalf("Forth Event was %v; want %v", ctx.upd.events[3].Type, structs.TaskStarted)
   442  	}
   443  
   444  	if ctx.upd.events[4].Type != structs.TaskTerminated {
   445  		t.Fatalf("Fifth Event was %v; want %v", ctx.upd.events[4].Type, structs.TaskTerminated)
   446  	}
   447  
   448  	// Check that both files exist.
   449  	if _, err := os.Stat(filepath.Join(ctx.tr.taskDir.Dir, f1)); err != nil {
   450  		t.Fatalf("%v not downloaded", f1)
   451  	}
   452  	if _, err := os.Stat(filepath.Join(ctx.tr.taskDir.Dir, f2)); err != nil {
   453  		t.Fatalf("%v not downloaded", f2)
   454  	}
   455  }
   456  
   457  func TestTaskRunner_Download_Retries(t *testing.T) {
   458  	ctestutil.ExecCompatible(t)
   459  
   460  	// Create an allocation that has a task with bad artifacts.
   461  	alloc := mock.Alloc()
   462  	task := alloc.Job.TaskGroups[0].Tasks[0]
   463  	artifact := structs.TaskArtifact{
   464  		GetterSource: "http://127.1.1.111:12315/foo/bar/baz",
   465  	}
   466  	task.Artifacts = []*structs.TaskArtifact{&artifact}
   467  
   468  	// Make the restart policy try one ctx.upd.te
   469  	alloc.Job.TaskGroups[0].RestartPolicy = &structs.RestartPolicy{
   470  		Attempts: 1,
   471  		Interval: 10 * time.Minute,
   472  		Delay:    1 * time.Second,
   473  		Mode:     structs.RestartPolicyModeFail,
   474  	}
   475  
   476  	ctx := testTaskRunnerFromAlloc(t, true, alloc)
   477  	ctx.tr.MarkReceived()
   478  	go ctx.tr.Run()
   479  	defer ctx.Cleanup()
   480  
   481  	select {
   482  	case <-ctx.tr.WaitCh():
   483  	case <-time.After(time.Duration(testutil.TestMultiplier()*15) * time.Second):
   484  		t.Fatalf("timeout")
   485  	}
   486  
   487  	if len(ctx.upd.events) != 8 {
   488  		t.Fatalf("should have 8 ctx.updates: %#v", ctx.upd.events)
   489  	}
   490  
   491  	if ctx.upd.state != structs.TaskStateDead {
   492  		t.Fatalf("TaskState %v; want %v", ctx.upd.state, structs.TaskStateDead)
   493  	}
   494  
   495  	if ctx.upd.events[0].Type != structs.TaskReceived {
   496  		t.Fatalf("First Event was %v; want %v", ctx.upd.events[0].Type, structs.TaskReceived)
   497  	}
   498  
   499  	if ctx.upd.events[1].Type != structs.TaskSetup {
   500  		t.Fatalf("Second Event was %v; want %v", ctx.upd.events[1].Type, structs.TaskSetup)
   501  	}
   502  
   503  	if ctx.upd.events[2].Type != structs.TaskDownloadingArtifacts {
   504  		t.Fatalf("Third Event was %v; want %v", ctx.upd.events[2].Type, structs.TaskDownloadingArtifacts)
   505  	}
   506  
   507  	if ctx.upd.events[3].Type != structs.TaskArtifactDownloadFailed {
   508  		t.Fatalf("Fourth Event was %v; want %v", ctx.upd.events[3].Type, structs.TaskArtifactDownloadFailed)
   509  	}
   510  
   511  	if ctx.upd.events[4].Type != structs.TaskRestarting {
   512  		t.Fatalf("Fifth Event was %v; want %v", ctx.upd.events[4].Type, structs.TaskRestarting)
   513  	}
   514  
   515  	if ctx.upd.events[5].Type != structs.TaskDownloadingArtifacts {
   516  		t.Fatalf("Sixth Event was %v; want %v", ctx.upd.events[5].Type, structs.TaskDownloadingArtifacts)
   517  	}
   518  
   519  	if ctx.upd.events[6].Type != structs.TaskArtifactDownloadFailed {
   520  		t.Fatalf("Seventh Event was %v; want %v", ctx.upd.events[6].Type, structs.TaskArtifactDownloadFailed)
   521  	}
   522  
   523  	if ctx.upd.events[7].Type != structs.TaskNotRestarting {
   524  		t.Fatalf("Eighth Event was %v; want %v", ctx.upd.events[7].Type, structs.TaskNotRestarting)
   525  	}
   526  }
   527  
   528  func TestTaskRunner_Validate_UserEnforcement(t *testing.T) {
   529  	ctestutil.ExecCompatible(t)
   530  	ctx := testTaskRunner(t, false)
   531  	defer ctx.Cleanup()
   532  
   533  	if err := ctx.tr.setTaskEnv(); err != nil {
   534  		t.Fatalf("bad: %v", err)
   535  	}
   536  
   537  	// Try to run as root with exec.
   538  	ctx.tr.task.Driver = "exec"
   539  	ctx.tr.task.User = "root"
   540  	if err := ctx.tr.validateTask(); err == nil {
   541  		t.Fatalf("expected error running as root with exec")
   542  	}
   543  
   544  	// Try to run a non-blacklisted user with exec.
   545  	ctx.tr.task.Driver = "exec"
   546  	ctx.tr.task.User = "foobar"
   547  	if err := ctx.tr.validateTask(); err != nil {
   548  		t.Fatalf("unexpected error: %v", err)
   549  	}
   550  
   551  	// Try to run as root with docker.
   552  	ctx.tr.task.Driver = "docker"
   553  	ctx.tr.task.User = "root"
   554  	if err := ctx.tr.validateTask(); err != nil {
   555  		t.Fatalf("unexpected error: %v", err)
   556  	}
   557  }
   558  
   559  func TestTaskRunner_RestartTask(t *testing.T) {
   560  	alloc := mock.Alloc()
   561  	task := alloc.Job.TaskGroups[0].Tasks[0]
   562  	task.Driver = "mock_driver"
   563  	task.Config = map[string]interface{}{
   564  		"exit_code": "0",
   565  		"run_for":   "100s",
   566  	}
   567  
   568  	ctx := testTaskRunnerFromAlloc(t, true, alloc)
   569  	ctx.tr.MarkReceived()
   570  	go ctx.tr.Run()
   571  	defer ctx.Cleanup()
   572  
   573  	// Wait for it to start
   574  	go func() {
   575  		testWaitForTaskToStart(t, ctx)
   576  		ctx.tr.Restart("test", "restart")
   577  
   578  		// Wait for it to restart then kill
   579  		go func() {
   580  			// Wait for the task to start again
   581  			testutil.WaitForResult(func() (bool, error) {
   582  				if len(ctx.upd.events) != 8 {
   583  					t.Fatalf("task %q in alloc %q should have 8 ctx.updates: %#v", task.Name, alloc.ID, ctx.upd.events)
   584  				}
   585  
   586  				return true, nil
   587  			}, func(err error) {
   588  				t.Fatalf("err: %v", err)
   589  			})
   590  			ctx.tr.Kill("test", "restart", false)
   591  		}()
   592  	}()
   593  
   594  	select {
   595  	case <-ctx.tr.WaitCh():
   596  	case <-time.After(time.Duration(testutil.TestMultiplier()*15) * time.Second):
   597  		t.Fatalf("timeout")
   598  	}
   599  
   600  	if len(ctx.upd.events) != 10 {
   601  		t.Fatalf("should have 9 ctx.updates: %#v", ctx.upd.events)
   602  	}
   603  
   604  	if ctx.upd.state != structs.TaskStateDead {
   605  		t.Fatalf("TaskState %v; want %v", ctx.upd.state, structs.TaskStateDead)
   606  	}
   607  
   608  	if ctx.upd.events[0].Type != structs.TaskReceived {
   609  		t.Fatalf("First Event was %v; want %v", ctx.upd.events[0].Type, structs.TaskReceived)
   610  	}
   611  
   612  	if ctx.upd.events[1].Type != structs.TaskSetup {
   613  		t.Fatalf("Second Event was %v; want %v", ctx.upd.events[1].Type, structs.TaskSetup)
   614  	}
   615  
   616  	if ctx.upd.events[2].Type != structs.TaskStarted {
   617  		t.Fatalf("Third Event was %v; want %v", ctx.upd.events[2].Type, structs.TaskStarted)
   618  	}
   619  
   620  	if ctx.upd.events[3].Type != structs.TaskRestartSignal {
   621  		t.Fatalf("Fourth Event was %v; want %v", ctx.upd.events[3].Type, structs.TaskRestartSignal)
   622  	}
   623  
   624  	if ctx.upd.events[4].Type != structs.TaskKilling {
   625  		t.Fatalf("Fifth Event was %v; want %v", ctx.upd.events[4].Type, structs.TaskKilling)
   626  	}
   627  
   628  	if ctx.upd.events[5].Type != structs.TaskKilled {
   629  		t.Fatalf("Sixth Event was %v; want %v", ctx.upd.events[5].Type, structs.TaskKilled)
   630  	}
   631  
   632  	if ctx.upd.events[6].Type != structs.TaskRestarting {
   633  		t.Fatalf("Seventh Event was %v; want %v", ctx.upd.events[6].Type, structs.TaskRestarting)
   634  	}
   635  
   636  	if ctx.upd.events[7].Type != structs.TaskStarted {
   637  		t.Fatalf("Eighth Event was %v; want %v", ctx.upd.events[8].Type, structs.TaskStarted)
   638  	}
   639  	if ctx.upd.events[8].Type != structs.TaskKilling {
   640  		t.Fatalf("Nineth  Event was %v; want %v", ctx.upd.events[8].Type, structs.TaskKilling)
   641  	}
   642  
   643  	if ctx.upd.events[9].Type != structs.TaskKilled {
   644  		t.Fatalf("Tenth Event was %v; want %v", ctx.upd.events[9].Type, structs.TaskKilled)
   645  	}
   646  }
   647  
   648  // This test is just to make sure we are resilient to failures when a restart or
   649  // signal is triggered and the task is not running.
   650  func TestTaskRunner_RestartSignalTask_NotRunning(t *testing.T) {
   651  	alloc := mock.Alloc()
   652  	task := alloc.Job.TaskGroups[0].Tasks[0]
   653  	task.Driver = "mock_driver"
   654  	task.Config = map[string]interface{}{
   655  		"exit_code": "0",
   656  		"run_for":   "100s",
   657  	}
   658  
   659  	// Use vault to block the start
   660  	task.Vault = &structs.Vault{Policies: []string{"default"}}
   661  
   662  	ctx := testTaskRunnerFromAlloc(t, true, alloc)
   663  	ctx.tr.MarkReceived()
   664  	defer ctx.Cleanup()
   665  
   666  	// Control when we get a Vault token
   667  	token := "1234"
   668  	waitCh := make(chan struct{})
   669  	defer close(waitCh)
   670  	handler := func(*structs.Allocation, []string) (map[string]string, error) {
   671  		<-waitCh
   672  		return map[string]string{task.Name: token}, nil
   673  	}
   674  	ctx.tr.vaultClient.(*vaultclient.MockVaultClient).DeriveTokenFn = handler
   675  	go ctx.tr.Run()
   676  
   677  	select {
   678  	case <-ctx.tr.WaitCh():
   679  		t.Fatalf("premature exit")
   680  	case <-time.After(1 * time.Second):
   681  	}
   682  
   683  	// Send a signal and restart
   684  	if err := ctx.tr.Signal("test", "don't panic", syscall.SIGCHLD); err != nil {
   685  		t.Fatalf("Signalling errored: %v", err)
   686  	}
   687  
   688  	// Send a restart
   689  	ctx.tr.Restart("test", "don't panic")
   690  
   691  	if len(ctx.upd.events) != 2 {
   692  		t.Fatalf("should have 2 ctx.updates: %#v", ctx.upd.events)
   693  	}
   694  
   695  	if ctx.upd.state != structs.TaskStatePending {
   696  		t.Fatalf("TaskState %v; want %v", ctx.upd.state, structs.TaskStatePending)
   697  	}
   698  
   699  	if ctx.upd.events[0].Type != structs.TaskReceived {
   700  		t.Fatalf("First Event was %v; want %v", ctx.upd.events[0].Type, structs.TaskReceived)
   701  	}
   702  
   703  	if ctx.upd.events[1].Type != structs.TaskSetup {
   704  		t.Fatalf("Second Event was %v; want %v", ctx.upd.events[1].Type, structs.TaskSetup)
   705  	}
   706  }
   707  
   708  func TestTaskRunner_KillTask(t *testing.T) {
   709  	alloc := mock.Alloc()
   710  	task := alloc.Job.TaskGroups[0].Tasks[0]
   711  	task.Driver = "mock_driver"
   712  	task.Config = map[string]interface{}{
   713  		"exit_code": "0",
   714  		"run_for":   "10s",
   715  	}
   716  
   717  	ctx := testTaskRunnerFromAlloc(t, false, alloc)
   718  	ctx.tr.MarkReceived()
   719  	go ctx.tr.Run()
   720  	defer ctx.Cleanup()
   721  
   722  	go func() {
   723  		testWaitForTaskToStart(t, ctx)
   724  		ctx.tr.Kill("test", "kill", true)
   725  	}()
   726  
   727  	select {
   728  	case <-ctx.tr.WaitCh():
   729  	case <-time.After(time.Duration(testutil.TestMultiplier()*15) * time.Second):
   730  		t.Fatalf("timeout")
   731  	}
   732  
   733  	if len(ctx.upd.events) != 5 {
   734  		t.Fatalf("should have 4 ctx.updates: %#v", ctx.upd.events)
   735  	}
   736  
   737  	if ctx.upd.state != structs.TaskStateDead {
   738  		t.Fatalf("TaskState %v; want %v", ctx.upd.state, structs.TaskStateDead)
   739  	}
   740  
   741  	if !ctx.upd.failed {
   742  		t.Fatalf("TaskState should be failed: %+v", ctx.upd)
   743  	}
   744  
   745  	if ctx.upd.events[0].Type != structs.TaskReceived {
   746  		t.Fatalf("First Event was %v; want %v", ctx.upd.events[0].Type, structs.TaskReceived)
   747  	}
   748  
   749  	if ctx.upd.events[1].Type != structs.TaskSetup {
   750  		t.Fatalf("Second Event was %v; want %v", ctx.upd.events[1].Type, structs.TaskSetup)
   751  	}
   752  
   753  	if ctx.upd.events[2].Type != structs.TaskStarted {
   754  		t.Fatalf("Third Event was %v; want %v", ctx.upd.events[2].Type, structs.TaskStarted)
   755  	}
   756  
   757  	if ctx.upd.events[3].Type != structs.TaskKilling {
   758  		t.Fatalf("Fourth Event was %v; want %v", ctx.upd.events[3].Type, structs.TaskKilling)
   759  	}
   760  
   761  	if ctx.upd.events[4].Type != structs.TaskKilled {
   762  		t.Fatalf("Fifth Event was %v; want %v", ctx.upd.events[4].Type, structs.TaskKilled)
   763  	}
   764  }
   765  
   766  func TestTaskRunner_SignalFailure(t *testing.T) {
   767  	alloc := mock.Alloc()
   768  	task := alloc.Job.TaskGroups[0].Tasks[0]
   769  	task.Driver = "mock_driver"
   770  	task.Config = map[string]interface{}{
   771  		"exit_code":    "0",
   772  		"run_for":      "10s",
   773  		"signal_error": "test forcing failure",
   774  	}
   775  
   776  	ctx := testTaskRunnerFromAlloc(t, false, alloc)
   777  	ctx.tr.MarkReceived()
   778  	go ctx.tr.Run()
   779  	defer ctx.Cleanup()
   780  
   781  	// Wait for the task to start
   782  	testWaitForTaskToStart(t, ctx)
   783  
   784  	if err := ctx.tr.Signal("test", "test", syscall.SIGINT); err == nil {
   785  		t.Fatalf("Didn't receive error")
   786  	}
   787  }
   788  
   789  func TestTaskRunner_BlockForVault(t *testing.T) {
   790  	alloc := mock.Alloc()
   791  	task := alloc.Job.TaskGroups[0].Tasks[0]
   792  	task.Driver = "mock_driver"
   793  	task.Config = map[string]interface{}{
   794  		"exit_code": "0",
   795  		"run_for":   "1s",
   796  	}
   797  	task.Vault = &structs.Vault{Policies: []string{"default"}}
   798  
   799  	ctx := testTaskRunnerFromAlloc(t, false, alloc)
   800  	ctx.tr.MarkReceived()
   801  	defer ctx.Cleanup()
   802  
   803  	// Control when we get a Vault token
   804  	token := "1234"
   805  	waitCh := make(chan struct{})
   806  	handler := func(*structs.Allocation, []string) (map[string]string, error) {
   807  		<-waitCh
   808  		return map[string]string{task.Name: token}, nil
   809  	}
   810  	ctx.tr.vaultClient.(*vaultclient.MockVaultClient).DeriveTokenFn = handler
   811  
   812  	go ctx.tr.Run()
   813  
   814  	select {
   815  	case <-ctx.tr.WaitCh():
   816  		t.Fatalf("premature exit")
   817  	case <-time.After(1 * time.Second):
   818  	}
   819  
   820  	if len(ctx.upd.events) != 2 {
   821  		t.Fatalf("should have 2 ctx.updates: %#v", ctx.upd.events)
   822  	}
   823  
   824  	if ctx.upd.state != structs.TaskStatePending {
   825  		t.Fatalf("TaskState %v; want %v", ctx.upd.state, structs.TaskStatePending)
   826  	}
   827  
   828  	if ctx.upd.events[0].Type != structs.TaskReceived {
   829  		t.Fatalf("First Event was %v; want %v", ctx.upd.events[0].Type, structs.TaskReceived)
   830  	}
   831  
   832  	if ctx.upd.events[1].Type != structs.TaskSetup {
   833  		t.Fatalf("Second Event was %v; want %v", ctx.upd.events[1].Type, structs.TaskSetup)
   834  	}
   835  
   836  	// Unblock
   837  	close(waitCh)
   838  
   839  	select {
   840  	case <-ctx.tr.WaitCh():
   841  	case <-time.After(time.Duration(testutil.TestMultiplier()*15) * time.Second):
   842  		t.Fatalf("timeout")
   843  	}
   844  
   845  	if len(ctx.upd.events) != 4 {
   846  		t.Fatalf("should have 4 ctx.updates: %#v", ctx.upd.events)
   847  	}
   848  
   849  	if ctx.upd.state != structs.TaskStateDead {
   850  		t.Fatalf("TaskState %v; want %v", ctx.upd.state, structs.TaskStateDead)
   851  	}
   852  
   853  	if ctx.upd.events[0].Type != structs.TaskReceived {
   854  		t.Fatalf("First Event was %v; want %v", ctx.upd.events[0].Type, structs.TaskReceived)
   855  	}
   856  
   857  	if ctx.upd.events[1].Type != structs.TaskSetup {
   858  		t.Fatalf("Second Event was %v; want %v", ctx.upd.events[1].Type, structs.TaskSetup)
   859  	}
   860  
   861  	if ctx.upd.events[2].Type != structs.TaskStarted {
   862  		t.Fatalf("Third Event was %v; want %v", ctx.upd.events[2].Type, structs.TaskStarted)
   863  	}
   864  
   865  	if ctx.upd.events[3].Type != structs.TaskTerminated {
   866  		t.Fatalf("Fourth Event was %v; want %v", ctx.upd.events[3].Type, structs.TaskTerminated)
   867  	}
   868  
   869  	// Check that the token is on disk
   870  	tokenPath := filepath.Join(ctx.tr.taskDir.SecretsDir, vaultTokenFile)
   871  	data, err := ioutil.ReadFile(tokenPath)
   872  	if err != nil {
   873  		t.Fatalf("Failed to read file: %v", err)
   874  	}
   875  
   876  	if act := string(data); act != token {
   877  		t.Fatalf("Token didn't get written to disk properly, got %q; want %q", act, token)
   878  	}
   879  
   880  	// Check the token was revoked
   881  	m := ctx.tr.vaultClient.(*vaultclient.MockVaultClient)
   882  	testutil.WaitForResult(func() (bool, error) {
   883  		if len(m.StoppedTokens) != 1 {
   884  			return false, fmt.Errorf("Expected a stopped token: %v", m.StoppedTokens)
   885  		}
   886  
   887  		if a := m.StoppedTokens[0]; a != token {
   888  			return false, fmt.Errorf("got stopped token %q; want %q", a, token)
   889  		}
   890  		return true, nil
   891  	}, func(err error) {
   892  		t.Fatalf("err: %v", err)
   893  	})
   894  }
   895  
   896  func TestTaskRunner_DeriveToken_Retry(t *testing.T) {
   897  	alloc := mock.Alloc()
   898  	task := alloc.Job.TaskGroups[0].Tasks[0]
   899  	task.Driver = "mock_driver"
   900  	task.Config = map[string]interface{}{
   901  		"exit_code": "0",
   902  		"run_for":   "1s",
   903  	}
   904  	task.Vault = &structs.Vault{Policies: []string{"default"}}
   905  
   906  	ctx := testTaskRunnerFromAlloc(t, false, alloc)
   907  	ctx.tr.MarkReceived()
   908  	defer ctx.Cleanup()
   909  
   910  	// Control when we get a Vault token
   911  	token := "1234"
   912  	count := 0
   913  	handler := func(*structs.Allocation, []string) (map[string]string, error) {
   914  		if count > 0 {
   915  			return map[string]string{task.Name: token}, nil
   916  		}
   917  
   918  		count++
   919  		return nil, structs.NewRecoverableError(fmt.Errorf("Want a retry"), true)
   920  	}
   921  	ctx.tr.vaultClient.(*vaultclient.MockVaultClient).DeriveTokenFn = handler
   922  	go ctx.tr.Run()
   923  
   924  	select {
   925  	case <-ctx.tr.WaitCh():
   926  	case <-time.After(time.Duration(testutil.TestMultiplier()*15) * time.Second):
   927  		t.Fatalf("timeout")
   928  	}
   929  
   930  	if len(ctx.upd.events) != 4 {
   931  		t.Fatalf("should have 4 ctx.updates: %#v", ctx.upd.events)
   932  	}
   933  
   934  	if ctx.upd.state != structs.TaskStateDead {
   935  		t.Fatalf("TaskState %v; want %v", ctx.upd.state, structs.TaskStateDead)
   936  	}
   937  
   938  	if ctx.upd.events[0].Type != structs.TaskReceived {
   939  		t.Fatalf("First Event was %v; want %v", ctx.upd.events[0].Type, structs.TaskReceived)
   940  	}
   941  
   942  	if ctx.upd.events[1].Type != structs.TaskSetup {
   943  		t.Fatalf("Second Event was %v; want %v", ctx.upd.events[1].Type, structs.TaskSetup)
   944  	}
   945  
   946  	if ctx.upd.events[2].Type != structs.TaskStarted {
   947  		t.Fatalf("Third Event was %v; want %v", ctx.upd.events[2].Type, structs.TaskStarted)
   948  	}
   949  
   950  	if ctx.upd.events[3].Type != structs.TaskTerminated {
   951  		t.Fatalf("Fourth Event was %v; want %v", ctx.upd.events[3].Type, structs.TaskTerminated)
   952  	}
   953  
   954  	// Check that the token is on disk
   955  	tokenPath := filepath.Join(ctx.tr.taskDir.SecretsDir, vaultTokenFile)
   956  	data, err := ioutil.ReadFile(tokenPath)
   957  	if err != nil {
   958  		t.Fatalf("Failed to read file: %v", err)
   959  	}
   960  
   961  	if act := string(data); act != token {
   962  		t.Fatalf("Token didn't get written to disk properly, got %q; want %q", act, token)
   963  	}
   964  
   965  	// Check the token was revoked
   966  	m := ctx.tr.vaultClient.(*vaultclient.MockVaultClient)
   967  	testutil.WaitForResult(func() (bool, error) {
   968  		if len(m.StoppedTokens) != 1 {
   969  			return false, fmt.Errorf("Expected a stopped token: %v", m.StoppedTokens)
   970  		}
   971  
   972  		if a := m.StoppedTokens[0]; a != token {
   973  			return false, fmt.Errorf("got stopped token %q; want %q", a, token)
   974  		}
   975  		return true, nil
   976  	}, func(err error) {
   977  		t.Fatalf("err: %v", err)
   978  	})
   979  }
   980  
   981  func TestTaskRunner_DeriveToken_Unrecoverable(t *testing.T) {
   982  	alloc := mock.Alloc()
   983  	task := alloc.Job.TaskGroups[0].Tasks[0]
   984  	task.Driver = "mock_driver"
   985  	task.Config = map[string]interface{}{
   986  		"exit_code": "0",
   987  		"run_for":   "10s",
   988  	}
   989  	task.Vault = &structs.Vault{
   990  		Policies:   []string{"default"},
   991  		ChangeMode: structs.VaultChangeModeRestart,
   992  	}
   993  
   994  	ctx := testTaskRunnerFromAlloc(t, false, alloc)
   995  	ctx.tr.MarkReceived()
   996  	defer ctx.Cleanup()
   997  
   998  	// Error the token derivation
   999  	vc := ctx.tr.vaultClient.(*vaultclient.MockVaultClient)
  1000  	vc.SetDeriveTokenError(alloc.ID, []string{task.Name}, fmt.Errorf("Non recoverable"))
  1001  	go ctx.tr.Run()
  1002  
  1003  	// Wait for the task to start
  1004  	testutil.WaitForResult(func() (bool, error) {
  1005  		if l := len(ctx.upd.events); l != 3 {
  1006  			return false, fmt.Errorf("Expect 3 events; got %v", l)
  1007  		}
  1008  
  1009  		if ctx.upd.events[0].Type != structs.TaskReceived {
  1010  			return false, fmt.Errorf("First Event was %v; want %v", ctx.upd.events[0].Type, structs.TaskReceived)
  1011  		}
  1012  
  1013  		if ctx.upd.events[1].Type != structs.TaskSetup {
  1014  			return false, fmt.Errorf("Second Event was %v; want %v", ctx.upd.events[1].Type, structs.TaskSetup)
  1015  		}
  1016  
  1017  		if ctx.upd.events[2].Type != structs.TaskKilling {
  1018  			return false, fmt.Errorf("Third Event was %v; want %v", ctx.upd.events[2].Type, structs.TaskKilling)
  1019  		}
  1020  
  1021  		return true, nil
  1022  	}, func(err error) {
  1023  		t.Fatalf("err: %v", err)
  1024  	})
  1025  }
  1026  
  1027  func TestTaskRunner_Template_Block(t *testing.T) {
  1028  	testRetryRate = 2 * time.Second
  1029  	defer func() {
  1030  		testRetryRate = 0
  1031  	}()
  1032  	alloc := mock.Alloc()
  1033  	task := alloc.Job.TaskGroups[0].Tasks[0]
  1034  	task.Driver = "mock_driver"
  1035  	task.Config = map[string]interface{}{
  1036  		"exit_code": "0",
  1037  		"run_for":   "1s",
  1038  	}
  1039  	task.Templates = []*structs.Template{
  1040  		{
  1041  			EmbeddedTmpl: "{{key \"foo\"}}",
  1042  			DestPath:     "local/test",
  1043  			ChangeMode:   structs.TemplateChangeModeNoop,
  1044  		},
  1045  	}
  1046  
  1047  	ctx := testTaskRunnerFromAlloc(t, false, alloc)
  1048  	ctx.tr.MarkReceived()
  1049  	go ctx.tr.Run()
  1050  	defer ctx.Cleanup()
  1051  
  1052  	select {
  1053  	case <-ctx.tr.WaitCh():
  1054  		t.Fatalf("premature exit")
  1055  	case <-time.After(1 * time.Second):
  1056  	}
  1057  
  1058  	if len(ctx.upd.events) != 2 {
  1059  		t.Fatalf("should have 2 ctx.updates: %#v", ctx.upd.events)
  1060  	}
  1061  
  1062  	if ctx.upd.state != structs.TaskStatePending {
  1063  		t.Fatalf("TaskState %v; want %v", ctx.upd.state, structs.TaskStatePending)
  1064  	}
  1065  
  1066  	if ctx.upd.events[0].Type != structs.TaskReceived {
  1067  		t.Fatalf("First Event was %v; want %v", ctx.upd.events[0].Type, structs.TaskReceived)
  1068  	}
  1069  
  1070  	if ctx.upd.events[1].Type != structs.TaskSetup {
  1071  		t.Fatalf("Second Event was %v; want %v", ctx.upd.events[1].Type, structs.TaskSetup)
  1072  	}
  1073  
  1074  	// Unblock
  1075  	ctx.tr.UnblockStart("test")
  1076  
  1077  	select {
  1078  	case <-ctx.tr.WaitCh():
  1079  	case <-time.After(time.Duration(testutil.TestMultiplier()*15) * time.Second):
  1080  		t.Fatalf("timeout")
  1081  	}
  1082  
  1083  	if len(ctx.upd.events) != 4 {
  1084  		t.Fatalf("should have 4 ctx.updates: %#v", ctx.upd.events)
  1085  	}
  1086  
  1087  	if ctx.upd.state != structs.TaskStateDead {
  1088  		t.Fatalf("TaskState %v; want %v", ctx.upd.state, structs.TaskStateDead)
  1089  	}
  1090  
  1091  	if ctx.upd.events[0].Type != structs.TaskReceived {
  1092  		t.Fatalf("First Event was %v; want %v", ctx.upd.events[0].Type, structs.TaskReceived)
  1093  	}
  1094  
  1095  	if ctx.upd.events[1].Type != structs.TaskSetup {
  1096  		t.Fatalf("Second Event was %v; want %v", ctx.upd.events[1].Type, structs.TaskSetup)
  1097  	}
  1098  
  1099  	if ctx.upd.events[2].Type != structs.TaskStarted {
  1100  		t.Fatalf("Third Event was %v; want %v", ctx.upd.events[2].Type, structs.TaskStarted)
  1101  	}
  1102  
  1103  	if ctx.upd.events[3].Type != structs.TaskTerminated {
  1104  		t.Fatalf("Fourth Event was %v; want %v", ctx.upd.events[3].Type, structs.TaskTerminated)
  1105  	}
  1106  }
  1107  
  1108  func TestTaskRunner_Template_Artifact(t *testing.T) {
  1109  	dir, err := os.Getwd()
  1110  	if err != nil {
  1111  		t.Fatalf("bad: %v", err)
  1112  	}
  1113  
  1114  	ts := httptest.NewServer(http.FileServer(http.Dir(filepath.Join(dir, ".."))))
  1115  	defer ts.Close()
  1116  
  1117  	alloc := mock.Alloc()
  1118  	task := alloc.Job.TaskGroups[0].Tasks[0]
  1119  	task.Driver = "mock_driver"
  1120  	task.Config = map[string]interface{}{
  1121  		"exit_code": "0",
  1122  		"run_for":   "1s",
  1123  	}
  1124  	// Create an allocation that has a task that renders a template from an
  1125  	// artifact
  1126  	f1 := "CHANGELOG.md"
  1127  	artifact := structs.TaskArtifact{
  1128  		GetterSource: fmt.Sprintf("%s/%s", ts.URL, f1),
  1129  	}
  1130  	task.Artifacts = []*structs.TaskArtifact{&artifact}
  1131  	task.Templates = []*structs.Template{
  1132  		{
  1133  			SourcePath: "CHANGELOG.md",
  1134  			DestPath:   "local/test",
  1135  			ChangeMode: structs.TemplateChangeModeNoop,
  1136  		},
  1137  	}
  1138  
  1139  	ctx := testTaskRunnerFromAlloc(t, false, alloc)
  1140  	ctx.tr.MarkReceived()
  1141  	defer ctx.Cleanup()
  1142  	go ctx.tr.Run()
  1143  
  1144  	select {
  1145  	case <-ctx.tr.WaitCh():
  1146  	case <-time.After(time.Duration(testutil.TestMultiplier()*15) * time.Second):
  1147  		t.Fatalf("timeout")
  1148  	}
  1149  
  1150  	if len(ctx.upd.events) != 5 {
  1151  		t.Fatalf("should have 5 ctx.updates: %#v", ctx.upd.events)
  1152  	}
  1153  
  1154  	if ctx.upd.state != structs.TaskStateDead {
  1155  		t.Fatalf("TaskState %v; want %v", ctx.upd.state, structs.TaskStateDead)
  1156  	}
  1157  
  1158  	if ctx.upd.events[0].Type != structs.TaskReceived {
  1159  		t.Fatalf("First Event was %v; want %v", ctx.upd.events[0].Type, structs.TaskReceived)
  1160  	}
  1161  
  1162  	if ctx.upd.events[1].Type != structs.TaskSetup {
  1163  		t.Fatalf("Second Event was %v; want %v", ctx.upd.events[1].Type, structs.TaskSetup)
  1164  	}
  1165  
  1166  	if ctx.upd.events[2].Type != structs.TaskDownloadingArtifacts {
  1167  		t.Fatalf("Third Event was %v; want %v", ctx.upd.events[2].Type, structs.TaskDownloadingArtifacts)
  1168  	}
  1169  
  1170  	if ctx.upd.events[3].Type != structs.TaskStarted {
  1171  		t.Fatalf("Fourth Event was %v; want %v", ctx.upd.events[3].Type, structs.TaskStarted)
  1172  	}
  1173  
  1174  	if ctx.upd.events[4].Type != structs.TaskTerminated {
  1175  		t.Fatalf("Fifth Event was %v; want %v", ctx.upd.events[4].Type, structs.TaskTerminated)
  1176  	}
  1177  
  1178  	// Check that both files exist.
  1179  	if _, err := os.Stat(filepath.Join(ctx.tr.taskDir.Dir, f1)); err != nil {
  1180  		t.Fatalf("%v not downloaded", f1)
  1181  	}
  1182  	if _, err := os.Stat(filepath.Join(ctx.tr.taskDir.LocalDir, "test")); err != nil {
  1183  		t.Fatalf("template not rendered")
  1184  	}
  1185  }
  1186  
  1187  func TestTaskRunner_Template_NewVaultToken(t *testing.T) {
  1188  	alloc := mock.Alloc()
  1189  	task := alloc.Job.TaskGroups[0].Tasks[0]
  1190  	task.Driver = "mock_driver"
  1191  	task.Config = map[string]interface{}{
  1192  		"exit_code": "0",
  1193  		"run_for":   "1s",
  1194  	}
  1195  	task.Templates = []*structs.Template{
  1196  		{
  1197  			EmbeddedTmpl: "{{key \"foo\"}}",
  1198  			DestPath:     "local/test",
  1199  			ChangeMode:   structs.TemplateChangeModeNoop,
  1200  		},
  1201  	}
  1202  	task.Vault = &structs.Vault{Policies: []string{"default"}}
  1203  
  1204  	ctx := testTaskRunnerFromAlloc(t, false, alloc)
  1205  	ctx.tr.MarkReceived()
  1206  	defer ctx.Cleanup()
  1207  	go ctx.tr.Run()
  1208  
  1209  	// Wait for a Vault token
  1210  	var token string
  1211  	testutil.WaitForResult(func() (bool, error) {
  1212  		if token = ctx.tr.vaultFuture.Get(); token == "" {
  1213  			return false, fmt.Errorf("No Vault token")
  1214  		}
  1215  
  1216  		return true, nil
  1217  	}, func(err error) {
  1218  		t.Fatalf("err: %v", err)
  1219  	})
  1220  
  1221  	// Error the token renewal
  1222  	vc := ctx.tr.vaultClient.(*vaultclient.MockVaultClient)
  1223  	renewalCh, ok := vc.RenewTokens[token]
  1224  	if !ok {
  1225  		t.Fatalf("no renewal channel")
  1226  	}
  1227  
  1228  	originalManager := ctx.tr.templateManager
  1229  
  1230  	renewalCh <- fmt.Errorf("Test killing")
  1231  	close(renewalCh)
  1232  
  1233  	// Wait for a new Vault token
  1234  	var token2 string
  1235  	testutil.WaitForResult(func() (bool, error) {
  1236  		if token2 = ctx.tr.vaultFuture.Get(); token2 == "" || token2 == token {
  1237  			return false, fmt.Errorf("No new Vault token")
  1238  		}
  1239  
  1240  		if originalManager == ctx.tr.templateManager {
  1241  			return false, fmt.Errorf("Template manager not ctx.updated")
  1242  		}
  1243  
  1244  		return true, nil
  1245  	}, func(err error) {
  1246  		t.Fatalf("err: %v", err)
  1247  	})
  1248  
  1249  	// Check the token was revoked
  1250  	m := ctx.tr.vaultClient.(*vaultclient.MockVaultClient)
  1251  	testutil.WaitForResult(func() (bool, error) {
  1252  		if len(m.StoppedTokens) != 1 {
  1253  			return false, fmt.Errorf("Expected a stopped token: %v", m.StoppedTokens)
  1254  		}
  1255  
  1256  		if a := m.StoppedTokens[0]; a != token {
  1257  			return false, fmt.Errorf("got stopped token %q; want %q", a, token)
  1258  		}
  1259  		return true, nil
  1260  	}, func(err error) {
  1261  		t.Fatalf("err: %v", err)
  1262  	})
  1263  }
  1264  
  1265  func TestTaskRunner_VaultManager_Restart(t *testing.T) {
  1266  	alloc := mock.Alloc()
  1267  	task := alloc.Job.TaskGroups[0].Tasks[0]
  1268  	task.Driver = "mock_driver"
  1269  	task.Config = map[string]interface{}{
  1270  		"exit_code": "0",
  1271  		"run_for":   "10s",
  1272  	}
  1273  	task.Vault = &structs.Vault{
  1274  		Policies:   []string{"default"},
  1275  		ChangeMode: structs.VaultChangeModeRestart,
  1276  	}
  1277  
  1278  	ctx := testTaskRunnerFromAlloc(t, false, alloc)
  1279  	ctx.tr.MarkReceived()
  1280  	defer ctx.Cleanup()
  1281  	go ctx.tr.Run()
  1282  
  1283  	// Wait for the task to start
  1284  	testWaitForTaskToStart(t, ctx)
  1285  
  1286  	// Error the token renewal
  1287  	vc := ctx.tr.vaultClient.(*vaultclient.MockVaultClient)
  1288  	renewalCh, ok := vc.RenewTokens[ctx.tr.vaultFuture.Get()]
  1289  	if !ok {
  1290  		t.Fatalf("no renewal channel")
  1291  	}
  1292  
  1293  	renewalCh <- fmt.Errorf("Test killing")
  1294  	close(renewalCh)
  1295  
  1296  	// Ensure a restart
  1297  	testutil.WaitForResult(func() (bool, error) {
  1298  		if l := len(ctx.upd.events); l != 8 {
  1299  			return false, fmt.Errorf("Expect eight events; got %#v", ctx.upd.events)
  1300  		}
  1301  
  1302  		if ctx.upd.events[0].Type != structs.TaskReceived {
  1303  			return false, fmt.Errorf("First Event was %v; want %v", ctx.upd.events[0].Type, structs.TaskReceived)
  1304  		}
  1305  
  1306  		if ctx.upd.events[1].Type != structs.TaskSetup {
  1307  			return false, fmt.Errorf("Second Event was %v; want %v", ctx.upd.events[1].Type, structs.TaskStarted)
  1308  		}
  1309  
  1310  		if ctx.upd.events[2].Type != structs.TaskStarted {
  1311  			return false, fmt.Errorf("Third Event was %v; want %v", ctx.upd.events[2].Type, structs.TaskStarted)
  1312  		}
  1313  
  1314  		if ctx.upd.events[3].Type != structs.TaskRestartSignal {
  1315  			return false, fmt.Errorf("Fourth Event was %v; want %v", ctx.upd.events[3].Type, structs.TaskRestartSignal)
  1316  		}
  1317  
  1318  		if ctx.upd.events[4].Type != structs.TaskKilling {
  1319  			return false, fmt.Errorf("Fifth Event was %v; want %v", ctx.upd.events[4].Type, structs.TaskKilling)
  1320  		}
  1321  
  1322  		if ctx.upd.events[5].Type != structs.TaskKilled {
  1323  			return false, fmt.Errorf("Sixth Event was %v; want %v", ctx.upd.events[5].Type, structs.TaskKilled)
  1324  		}
  1325  
  1326  		if ctx.upd.events[6].Type != structs.TaskRestarting {
  1327  			return false, fmt.Errorf("Seventh Event was %v; want %v", ctx.upd.events[6].Type, structs.TaskRestarting)
  1328  		}
  1329  
  1330  		if ctx.upd.events[7].Type != structs.TaskStarted {
  1331  			return false, fmt.Errorf("Eight Event was %v; want %v", ctx.upd.events[7].Type, structs.TaskStarted)
  1332  		}
  1333  
  1334  		return true, nil
  1335  	}, func(err error) {
  1336  		t.Fatalf("err: %v", err)
  1337  	})
  1338  }
  1339  
  1340  func TestTaskRunner_VaultManager_Signal(t *testing.T) {
  1341  	alloc := mock.Alloc()
  1342  	task := alloc.Job.TaskGroups[0].Tasks[0]
  1343  	task.Driver = "mock_driver"
  1344  	task.Config = map[string]interface{}{
  1345  		"exit_code": "0",
  1346  		"run_for":   "10s",
  1347  	}
  1348  	task.Vault = &structs.Vault{
  1349  		Policies:     []string{"default"},
  1350  		ChangeMode:   structs.VaultChangeModeSignal,
  1351  		ChangeSignal: "SIGUSR1",
  1352  	}
  1353  
  1354  	ctx := testTaskRunnerFromAlloc(t, false, alloc)
  1355  	ctx.tr.MarkReceived()
  1356  	go ctx.tr.Run()
  1357  	defer ctx.Cleanup()
  1358  
  1359  	// Wait for the task to start
  1360  	testWaitForTaskToStart(t, ctx)
  1361  
  1362  	// Error the token renewal
  1363  	vc := ctx.tr.vaultClient.(*vaultclient.MockVaultClient)
  1364  	renewalCh, ok := vc.RenewTokens[ctx.tr.vaultFuture.Get()]
  1365  	if !ok {
  1366  		t.Fatalf("no renewal channel")
  1367  	}
  1368  
  1369  	renewalCh <- fmt.Errorf("Test killing")
  1370  	close(renewalCh)
  1371  
  1372  	// Ensure a restart
  1373  	testutil.WaitForResult(func() (bool, error) {
  1374  		if l := len(ctx.upd.events); l != 4 {
  1375  			return false, fmt.Errorf("Expect four events; got %#v", ctx.upd.events)
  1376  		}
  1377  
  1378  		if ctx.upd.events[0].Type != structs.TaskReceived {
  1379  			return false, fmt.Errorf("First Event was %v; want %v", ctx.upd.events[0].Type, structs.TaskReceived)
  1380  		}
  1381  
  1382  		if ctx.upd.events[1].Type != structs.TaskSetup {
  1383  			return false, fmt.Errorf("Second Event was %v; want %v", ctx.upd.events[1].Type, structs.TaskSetup)
  1384  		}
  1385  
  1386  		if ctx.upd.events[2].Type != structs.TaskStarted {
  1387  			return false, fmt.Errorf("Third Event was %v; want %v", ctx.upd.events[2].Type, structs.TaskStarted)
  1388  		}
  1389  
  1390  		if ctx.upd.events[3].Type != structs.TaskSignaling {
  1391  			return false, fmt.Errorf("Fourth Event was %v; want %v", ctx.upd.events[3].Type, structs.TaskSignaling)
  1392  		}
  1393  
  1394  		return true, nil
  1395  	}, func(err error) {
  1396  		t.Fatalf("err: %v", err)
  1397  	})
  1398  }
  1399  
  1400  // Test that the payload is written to disk
  1401  func TestTaskRunner_SimpleRun_Dispatch(t *testing.T) {
  1402  	alloc := mock.Alloc()
  1403  	task := alloc.Job.TaskGroups[0].Tasks[0]
  1404  	task.Driver = "mock_driver"
  1405  	task.Config = map[string]interface{}{
  1406  		"exit_code": "0",
  1407  		"run_for":   "1s",
  1408  	}
  1409  	fileName := "test"
  1410  	task.DispatchPayload = &structs.DispatchPayloadConfig{
  1411  		File: fileName,
  1412  	}
  1413  	alloc.Job.ParameterizedJob = &structs.ParameterizedJobConfig{}
  1414  
  1415  	// Add an encrypted payload
  1416  	expected := []byte("hello world")
  1417  	compressed := snappy.Encode(nil, expected)
  1418  	alloc.Job.Payload = compressed
  1419  
  1420  	ctx := testTaskRunnerFromAlloc(t, false, alloc)
  1421  	ctx.tr.MarkReceived()
  1422  	defer ctx.tr.Destroy(structs.NewTaskEvent(structs.TaskKilled))
  1423  	defer ctx.allocDir.Destroy()
  1424  	go ctx.tr.Run()
  1425  
  1426  	select {
  1427  	case <-ctx.tr.WaitCh():
  1428  	case <-time.After(time.Duration(testutil.TestMultiplier()*15) * time.Second):
  1429  		t.Fatalf("timeout")
  1430  	}
  1431  
  1432  	if len(ctx.upd.events) != 4 {
  1433  		t.Fatalf("should have 4 updates: %#v", ctx.upd.events)
  1434  	}
  1435  
  1436  	if ctx.upd.state != structs.TaskStateDead {
  1437  		t.Fatalf("TaskState %v; want %v", ctx.upd.state, structs.TaskStateDead)
  1438  	}
  1439  
  1440  	if ctx.upd.events[0].Type != structs.TaskReceived {
  1441  		t.Fatalf("First Event was %v; want %v", ctx.upd.events[0].Type, structs.TaskReceived)
  1442  	}
  1443  
  1444  	if ctx.upd.events[1].Type != structs.TaskSetup {
  1445  		t.Fatalf("Second Event was %v; want %v", ctx.upd.events[1].Type, structs.TaskSetup)
  1446  	}
  1447  
  1448  	if ctx.upd.events[2].Type != structs.TaskStarted {
  1449  		t.Fatalf("Third Event was %v; want %v", ctx.upd.events[2].Type, structs.TaskStarted)
  1450  	}
  1451  
  1452  	if ctx.upd.events[3].Type != structs.TaskTerminated {
  1453  		t.Fatalf("Fourth Event was %v; want %v", ctx.upd.events[3].Type, structs.TaskTerminated)
  1454  	}
  1455  
  1456  	// Check that the file was written to disk properly
  1457  	payloadPath := filepath.Join(ctx.tr.taskDir.LocalDir, fileName)
  1458  	data, err := ioutil.ReadFile(payloadPath)
  1459  	if err != nil {
  1460  		t.Fatalf("Failed to read file: %v", err)
  1461  	}
  1462  	if !reflect.DeepEqual(data, expected) {
  1463  		t.Fatalf("Bad; got %v; want %v", string(data), string(expected))
  1464  	}
  1465  }
  1466  
  1467  // TestTaskRunner_CleanupEmpty ensures TaskRunner works when createdResources
  1468  // is empty.
  1469  func TestTaskRunner_CleanupEmpty(t *testing.T) {
  1470  	alloc := mock.Alloc()
  1471  	task := alloc.Job.TaskGroups[0].Tasks[0]
  1472  	task.Driver = "mock_driver"
  1473  
  1474  	ctx := testTaskRunnerFromAlloc(t, false, alloc)
  1475  	ctx.tr.MarkReceived()
  1476  
  1477  	defer ctx.Cleanup()
  1478  	ctx.tr.Run()
  1479  
  1480  	// Since we only failed once, createdResources should be empty
  1481  	if len(ctx.tr.createdResources.Resources) != 0 {
  1482  		t.Fatalf("createdResources should still be empty: %v", ctx.tr.createdResources)
  1483  	}
  1484  }
  1485  
  1486  func TestTaskRunner_CleanupOK(t *testing.T) {
  1487  	alloc := mock.Alloc()
  1488  	task := alloc.Job.TaskGroups[0].Tasks[0]
  1489  	task.Driver = "mock_driver"
  1490  	key := "ERR"
  1491  
  1492  	ctx := testTaskRunnerFromAlloc(t, false, alloc)
  1493  	ctx.tr.config.Options = map[string]string{
  1494  		"cleanup_fail_on":  key,
  1495  		"cleanup_fail_num": "1",
  1496  	}
  1497  	ctx.tr.MarkReceived()
  1498  
  1499  	ctx.tr.createdResources.Resources[key] = []string{"x", "y"}
  1500  	ctx.tr.createdResources.Resources["foo"] = []string{"z"}
  1501  
  1502  	defer ctx.Cleanup()
  1503  	ctx.tr.Run()
  1504  
  1505  	// Since we only failed once, createdResources should be empty
  1506  	if len(ctx.tr.createdResources.Resources) > 0 {
  1507  		t.Fatalf("expected all created resources to be removed: %#v", ctx.tr.createdResources.Resources)
  1508  	}
  1509  }
  1510  
  1511  func TestTaskRunner_CleanupFail(t *testing.T) {
  1512  	alloc := mock.Alloc()
  1513  	task := alloc.Job.TaskGroups[0].Tasks[0]
  1514  	task.Driver = "mock_driver"
  1515  	key := "ERR"
  1516  	ctx := testTaskRunnerFromAlloc(t, false, alloc)
  1517  	ctx.tr.config.Options = map[string]string{
  1518  		"cleanup_fail_on":  key,
  1519  		"cleanup_fail_num": "5",
  1520  	}
  1521  	ctx.tr.MarkReceived()
  1522  
  1523  	ctx.tr.createdResources.Resources[key] = []string{"x"}
  1524  	ctx.tr.createdResources.Resources["foo"] = []string{"y", "z"}
  1525  
  1526  	defer ctx.Cleanup()
  1527  	ctx.tr.Run()
  1528  
  1529  	// Since we failed > 3 times, the failed key should remain
  1530  	expected := map[string][]string{key: {"x"}}
  1531  	if !reflect.DeepEqual(expected, ctx.tr.createdResources.Resources) {
  1532  		t.Fatalf("expected %#v but found: %#v", expected, ctx.tr.createdResources.Resources)
  1533  	}
  1534  }