github.com/maier/nomad@v0.4.1-0.20161110003312-a9e3d0b8549d/client/allocdir/alloc_dir_test.go (about)

     1  package allocdir
     2  
     3  import (
     4  	"archive/tar"
     5  	"bytes"
     6  	"io"
     7  	"io/ioutil"
     8  	"log"
     9  	"os"
    10  	"path/filepath"
    11  	"reflect"
    12  	"runtime"
    13  	"strings"
    14  	"testing"
    15  
    16  	tomb "gopkg.in/tomb.v1"
    17  
    18  	"github.com/hashicorp/nomad/client/testutil"
    19  	"github.com/hashicorp/nomad/nomad/structs"
    20  )
    21  
    22  var (
    23  	osMountSharedDirSupport = map[string]bool{
    24  		"darwin": true,
    25  		"linux":  true,
    26  	}
    27  
    28  	t1 = &structs.Task{
    29  		Name:   "web",
    30  		Driver: "exec",
    31  		Config: map[string]interface{}{
    32  			"command": "/bin/date",
    33  			"args":    "+%s",
    34  		},
    35  		Resources: &structs.Resources{
    36  			DiskMB: 1,
    37  		},
    38  	}
    39  
    40  	t2 = &structs.Task{
    41  		Name:   "web2",
    42  		Driver: "exec",
    43  		Config: map[string]interface{}{
    44  			"command": "/bin/date",
    45  			"args":    "+%s",
    46  		},
    47  		Resources: &structs.Resources{
    48  			DiskMB: 1,
    49  		},
    50  	}
    51  )
    52  
    53  // Test that given a set of tasks, each task gets a directory and that directory
    54  // has the shared alloc dir inside of it.
    55  func TestAllocDir_BuildAlloc(t *testing.T) {
    56  	tmp, err := ioutil.TempDir("", "AllocDir")
    57  	if err != nil {
    58  		t.Fatalf("Couldn't create temp dir: %v", err)
    59  	}
    60  	defer os.RemoveAll(tmp)
    61  
    62  	d := NewAllocDir(tmp)
    63  	defer d.Destroy()
    64  	tasks := []*structs.Task{t1, t2}
    65  	if err := d.Build(tasks); err != nil {
    66  		t.Fatalf("Build(%v) failed: %v", tasks, err)
    67  	}
    68  
    69  	// Check that the AllocDir and each of the task directories exist.
    70  	if _, err := os.Stat(d.AllocDir); os.IsNotExist(err) {
    71  		t.Fatalf("Build(%v) didn't create AllocDir %v", tasks, d.AllocDir)
    72  	}
    73  
    74  	for _, task := range tasks {
    75  		tDir, ok := d.TaskDirs[task.Name]
    76  		if !ok {
    77  			t.Fatalf("Task directory not found for %v", task.Name)
    78  		}
    79  
    80  		if _, err := os.Stat(tDir); os.IsNotExist(err) {
    81  			t.Fatalf("Build(%v) didn't create TaskDir %v", tasks, tDir)
    82  		}
    83  
    84  		if _, err := os.Stat(filepath.Join(tDir, TaskSecrets)); os.IsNotExist(err) {
    85  			t.Fatalf("Build(%v) didn't create secret dir %v", tasks)
    86  		}
    87  	}
    88  }
    89  
    90  func TestAllocDir_LogDir(t *testing.T) {
    91  	tmp, err := ioutil.TempDir("", "AllocDir")
    92  	if err != nil {
    93  		t.Fatalf("Couldn't create temp dir: %v", err)
    94  	}
    95  	defer os.RemoveAll(tmp)
    96  
    97  	d := NewAllocDir(tmp)
    98  	defer d.Destroy()
    99  
   100  	expected := filepath.Join(d.AllocDir, SharedAllocName, LogDirName)
   101  	if d.LogDir() != expected {
   102  		t.Fatalf("expected: %v, got: %v", expected, d.LogDir())
   103  	}
   104  }
   105  
   106  func TestAllocDir_EmbedNonExistent(t *testing.T) {
   107  	tmp, err := ioutil.TempDir("", "AllocDir")
   108  	if err != nil {
   109  		t.Fatalf("Couldn't create temp dir: %v", err)
   110  	}
   111  	defer os.RemoveAll(tmp)
   112  
   113  	d := NewAllocDir(tmp)
   114  	defer d.Destroy()
   115  	tasks := []*structs.Task{t1, t2}
   116  	if err := d.Build(tasks); err != nil {
   117  		t.Fatalf("Build(%v) failed: %v", tasks, err)
   118  	}
   119  
   120  	fakeDir := "/foobarbaz"
   121  	task := tasks[0].Name
   122  	mapping := map[string]string{fakeDir: fakeDir}
   123  	if err := d.Embed(task, mapping); err != nil {
   124  		t.Fatalf("Embed(%v, %v) should should skip %v since it does not exist", task, mapping, fakeDir)
   125  	}
   126  }
   127  
   128  func TestAllocDir_EmbedDirs(t *testing.T) {
   129  	tmp, err := ioutil.TempDir("", "AllocDir")
   130  	if err != nil {
   131  		t.Fatalf("Couldn't create temp dir: %v", err)
   132  	}
   133  	defer os.RemoveAll(tmp)
   134  
   135  	d := NewAllocDir(tmp)
   136  	defer d.Destroy()
   137  	tasks := []*structs.Task{t1, t2}
   138  	if err := d.Build(tasks); err != nil {
   139  		t.Fatalf("Build(%v) failed: %v", tasks, err)
   140  	}
   141  
   142  	// Create a fake host directory, with a file, and a subfolder that contains
   143  	// a file.
   144  	host, err := ioutil.TempDir("", "AllocDirHost")
   145  	if err != nil {
   146  		t.Fatalf("Couldn't create temp dir: %v", err)
   147  	}
   148  	defer os.RemoveAll(host)
   149  
   150  	subDirName := "subdir"
   151  	subDir := filepath.Join(host, subDirName)
   152  	if err := os.MkdirAll(subDir, 0777); err != nil {
   153  		t.Fatalf("Failed to make subdir %v: %v", subDir, err)
   154  	}
   155  
   156  	file := "foo"
   157  	subFile := "bar"
   158  	if err := ioutil.WriteFile(filepath.Join(host, file), []byte{'a'}, 0777); err != nil {
   159  		t.Fatalf("Coudn't create file in host dir %v: %v", host, err)
   160  	}
   161  
   162  	if err := ioutil.WriteFile(filepath.Join(subDir, subFile), []byte{'a'}, 0777); err != nil {
   163  		t.Fatalf("Coudn't create file in host subdir %v: %v", subDir, err)
   164  	}
   165  
   166  	// Create mapping from host dir to task dir.
   167  	task := tasks[0].Name
   168  	taskDest := "bin/test/"
   169  	mapping := map[string]string{host: taskDest}
   170  	if err := d.Embed(task, mapping); err != nil {
   171  		t.Fatalf("Embed(%v, %v) failed: %v", task, mapping, err)
   172  	}
   173  
   174  	// Check that the embedding was done properly.
   175  	taskDir, ok := d.TaskDirs[task]
   176  	if !ok {
   177  		t.Fatalf("Task directory not found for %v", task)
   178  	}
   179  
   180  	exp := []string{filepath.Join(taskDir, taskDest, file), filepath.Join(taskDir, taskDest, subDirName, subFile)}
   181  	for _, e := range exp {
   182  		if _, err := os.Stat(e); os.IsNotExist(err) {
   183  			t.Fatalf("File %v not embeded: %v", e, err)
   184  		}
   185  	}
   186  }
   187  
   188  func TestAllocDir_MountSharedAlloc(t *testing.T) {
   189  	testutil.MountCompatible(t)
   190  	tmp, err := ioutil.TempDir("", "AllocDir")
   191  	if err != nil {
   192  		t.Fatalf("Couldn't create temp dir: %v", err)
   193  	}
   194  	defer os.RemoveAll(tmp)
   195  
   196  	d := NewAllocDir(tmp)
   197  	defer d.Destroy()
   198  	tasks := []*structs.Task{t1, t2}
   199  	if err := d.Build(tasks); err != nil {
   200  		t.Fatalf("Build(%v) failed: %v", tasks, err)
   201  	}
   202  
   203  	// Write a file to the shared dir.
   204  	exp := []byte{'f', 'o', 'o'}
   205  	file := "bar"
   206  	if err := ioutil.WriteFile(filepath.Join(d.SharedDir, file), exp, 0777); err != nil {
   207  		t.Fatalf("Couldn't write file to shared directory: %v", err)
   208  	}
   209  
   210  	for _, task := range tasks {
   211  		// Mount and then check that the file exists in the task directory.
   212  		if err := d.MountSharedDir(task.Name); err != nil {
   213  			if v, ok := osMountSharedDirSupport[runtime.GOOS]; v && ok {
   214  				t.Fatalf("MountSharedDir(%v) failed: %v", task.Name, err)
   215  			} else {
   216  				t.Skipf("MountShareDir(%v) failed, no OS support")
   217  			}
   218  		}
   219  
   220  		taskDir, ok := d.TaskDirs[task.Name]
   221  		if !ok {
   222  			t.Fatalf("Task directory not found for %v", task.Name)
   223  		}
   224  
   225  		taskFile := filepath.Join(taskDir, SharedAllocName, file)
   226  		act, err := ioutil.ReadFile(taskFile)
   227  		if err != nil {
   228  			t.Fatalf("Failed to read shared alloc file from task dir: %v", err)
   229  		}
   230  
   231  		if !reflect.DeepEqual(act, exp) {
   232  			t.Fatalf("Incorrect data read from task dir: want %v; got %v", exp, act)
   233  		}
   234  	}
   235  }
   236  
   237  func TestAllocDir_Snapshot(t *testing.T) {
   238  	tmp, err := ioutil.TempDir("", "AllocDir")
   239  	if err != nil {
   240  		t.Fatalf("Couldn't create temp dir: %v", err)
   241  	}
   242  	defer os.RemoveAll(tmp)
   243  
   244  	d := NewAllocDir(tmp)
   245  	defer d.Destroy()
   246  
   247  	tasks := []*structs.Task{t1, t2}
   248  	if err := d.Build(tasks); err != nil {
   249  		t.Fatalf("Build(%v) failed: %v", tasks, err)
   250  	}
   251  
   252  	dataDir := filepath.Join(d.SharedDir, "data")
   253  	taskDir := d.TaskDirs[t1.Name]
   254  	taskLocal := filepath.Join(taskDir, "local")
   255  
   256  	// Write a file to the shared dir.
   257  	exp := []byte{'f', 'o', 'o'}
   258  	file := "bar"
   259  	if err := ioutil.WriteFile(filepath.Join(dataDir, file), exp, 0777); err != nil {
   260  		t.Fatalf("Couldn't write file to shared directory: %v", err)
   261  	}
   262  
   263  	// Write a file to the task local
   264  	exp = []byte{'b', 'a', 'r'}
   265  	file1 := "lol"
   266  	if err := ioutil.WriteFile(filepath.Join(taskLocal, file1), exp, 0777); err != nil {
   267  		t.Fatalf("couldn't write to task local directory: %v", err)
   268  	}
   269  
   270  	var b bytes.Buffer
   271  	if err := d.Snapshot(&b); err != nil {
   272  		t.Fatalf("err: %v", err)
   273  	}
   274  
   275  	tr := tar.NewReader(&b)
   276  	var files []string
   277  	for {
   278  		hdr, err := tr.Next()
   279  		if err != nil && err != io.EOF {
   280  			t.Fatalf("err: %v", err)
   281  		}
   282  		if err == io.EOF {
   283  			break
   284  		}
   285  		if hdr.Typeflag == tar.TypeReg {
   286  			files = append(files, hdr.FileInfo().Name())
   287  		}
   288  	}
   289  
   290  	if len(files) != 2 {
   291  		t.Fatalf("bad files: %#v", files)
   292  	}
   293  }
   294  
   295  func TestAllocDir_Move(t *testing.T) {
   296  	tmp1, err := ioutil.TempDir("", "AllocDir")
   297  	if err != nil {
   298  		t.Fatalf("Couldn't create temp dir: %v", err)
   299  	}
   300  	defer os.RemoveAll(tmp1)
   301  
   302  	tmp2, err := ioutil.TempDir("", "AllocDir")
   303  	if err != nil {
   304  		t.Fatalf("Couldn't create temp dir: %v", err)
   305  	}
   306  	defer os.RemoveAll(tmp2)
   307  
   308  	// Create two alloc dirs
   309  	d1 := NewAllocDir(tmp1)
   310  	defer d1.Destroy()
   311  
   312  	d2 := NewAllocDir(tmp2)
   313  	defer d2.Destroy()
   314  
   315  	tasks := []*structs.Task{t1, t2}
   316  	if err := d1.Build(tasks); err != nil {
   317  		t.Fatalf("Build(%v) failed: %v", tasks, err)
   318  	}
   319  
   320  	if err := d2.Build(tasks); err != nil {
   321  		t.Fatalf("Build(%v) failed: %v", tasks, err)
   322  	}
   323  
   324  	dataDir := filepath.Join(d1.SharedDir, "data")
   325  	taskDir := d1.TaskDirs[t1.Name]
   326  	taskLocal := filepath.Join(taskDir, "local")
   327  
   328  	// Write a file to the shared dir.
   329  	exp := []byte{'f', 'o', 'o'}
   330  	file := "bar"
   331  	if err := ioutil.WriteFile(filepath.Join(dataDir, file), exp, 0777); err != nil {
   332  		t.Fatalf("Couldn't write file to shared directory: %v", err)
   333  	}
   334  
   335  	// Write a file to the task local
   336  	exp = []byte{'b', 'a', 'r'}
   337  	file1 := "lol"
   338  	if err := ioutil.WriteFile(filepath.Join(taskLocal, file1), exp, 0777); err != nil {
   339  		t.Fatalf("couldn't write to task local directory: %v", err)
   340  	}
   341  
   342  	// Move the d1 allocdir to d2
   343  	if err := d2.Move(d1, []*structs.Task{t1, t2}); err != nil {
   344  		t.Fatalf("err: %v", err)
   345  	}
   346  
   347  	// Ensure the files in d1 are present in d2
   348  	fi, err := os.Stat(filepath.Join(d2.SharedDir, "data", "bar"))
   349  	if err != nil || fi == nil {
   350  		t.Fatalf("data dir was not moved")
   351  	}
   352  
   353  	fi, err = os.Stat(filepath.Join(d2.TaskDirs[t1.Name], "local", "lol"))
   354  	if err != nil || fi == nil {
   355  		t.Fatalf("task local dir was not moved")
   356  	}
   357  }
   358  
   359  func TestAllocDir_EscapeChecking(t *testing.T) {
   360  	tmp, err := ioutil.TempDir("", "AllocDir")
   361  	if err != nil {
   362  		t.Fatalf("Couldn't create temp dir: %v", err)
   363  	}
   364  	defer os.RemoveAll(tmp)
   365  
   366  	d := NewAllocDir(tmp)
   367  	defer d.Destroy()
   368  	tasks := []*structs.Task{t1, t2}
   369  	if err := d.Build(tasks); err != nil {
   370  		t.Fatalf("Build(%v) failed: %v", tasks, err)
   371  	}
   372  
   373  	// Check that issuing calls that escape the alloc dir returns errors
   374  	// List
   375  	if _, err := d.List(".."); err == nil || !strings.Contains(err.Error(), "escapes") {
   376  		t.Fatalf("List of escaping path didn't error: %v", err)
   377  	}
   378  
   379  	// Stat
   380  	if _, err := d.Stat("../foo"); err == nil || !strings.Contains(err.Error(), "escapes") {
   381  		t.Fatalf("Stat of escaping path didn't error: %v", err)
   382  	}
   383  
   384  	// ReadAt
   385  	if _, err := d.ReadAt("../foo", 0); err == nil || !strings.Contains(err.Error(), "escapes") {
   386  		t.Fatalf("ReadAt of escaping path didn't error: %v", err)
   387  	}
   388  
   389  	// BlockUntilExists
   390  	tomb := tomb.Tomb{}
   391  	if _, err := d.BlockUntilExists("../foo", &tomb); err == nil || !strings.Contains(err.Error(), "escapes") {
   392  		t.Fatalf("BlockUntilExists of escaping path didn't error: %v", err)
   393  	}
   394  
   395  	// ChangeEvents
   396  	if _, err := d.ChangeEvents("../foo", 0, &tomb); err == nil || !strings.Contains(err.Error(), "escapes") {
   397  		t.Fatalf("ChangeEvents of escaping path didn't error: %v", err)
   398  	}
   399  }
   400  
   401  func TestAllocDir_ReadAt_SecretDir(t *testing.T) {
   402  	tmp, err := ioutil.TempDir("", "AllocDir")
   403  	if err != nil {
   404  		t.Fatalf("Couldn't create temp dir: %v", err)
   405  	}
   406  	defer os.RemoveAll(tmp)
   407  
   408  	d := NewAllocDir(tmp)
   409  	defer d.Destroy()
   410  	tasks := []*structs.Task{t1, t2}
   411  	if err := d.Build(tasks); err != nil {
   412  		t.Fatalf("Build(%v) failed: %v", tasks, err)
   413  	}
   414  
   415  	// ReadAt of secret dir should fail
   416  	secret := filepath.Join(t1.Name, TaskSecrets, "test_file")
   417  	if _, err := d.ReadAt(secret, 0); err == nil || !strings.Contains(err.Error(), "secret file prohibited") {
   418  		t.Fatalf("ReadAt of secret file didn't error: %v", err)
   419  	}
   420  }
   421  
   422  func TestAllocDir_SplitPath(t *testing.T) {
   423  	dir, err := ioutil.TempDir("/tmp", "tmpdirtest")
   424  	if err != nil {
   425  		log.Fatal(err)
   426  	}
   427  	defer os.RemoveAll(dir)
   428  
   429  	dest := filepath.Join(dir, "/foo/bar/baz")
   430  	if err := os.MkdirAll(dest, os.ModePerm); err != nil {
   431  		t.Fatalf("err: %v", err)
   432  	}
   433  
   434  	d := NewAllocDir(dir)
   435  	defer d.Destroy()
   436  
   437  	info, err := d.splitPath(dest)
   438  	if err != nil {
   439  		t.Fatalf("err: %v", err)
   440  	}
   441  	if len(info) != 6 {
   442  		t.Fatalf("expected: %v, actual: %v", 6, len(info))
   443  	}
   444  }
   445  
   446  func TestAllocDir_CreateDir(t *testing.T) {
   447  	dir, err := ioutil.TempDir("/tmp", "tmpdirtest")
   448  	if err != nil {
   449  		t.Fatalf("err: %v", err)
   450  	}
   451  	defer os.RemoveAll(dir)
   452  
   453  	// create a subdir and a file
   454  	subdir := filepath.Join(dir, "subdir")
   455  	if err := os.MkdirAll(subdir, 0760); err != nil {
   456  		t.Fatalf("err: %v", err)
   457  	}
   458  	subdirMode, err := os.Stat(subdir)
   459  	if err != nil {
   460  		t.Fatalf("err: %v", err)
   461  	}
   462  
   463  	// Create the above hierarchy under another destination
   464  	dir1, err := ioutil.TempDir("/tmp", "tempdirdest")
   465  	if err != nil {
   466  		t.Fatalf("err: %v", err)
   467  	}
   468  
   469  	d := NewAllocDir(dir)
   470  	defer d.Destroy()
   471  
   472  	if err := d.createDir(dir1, subdir); err != nil {
   473  		t.Fatalf("err: %v", err)
   474  	}
   475  
   476  	// Ensure that the subdir had the right perm
   477  	fi, err := os.Stat(filepath.Join(dir1, dir, "subdir"))
   478  	if err != nil {
   479  		t.Fatalf("err: %v", err)
   480  	}
   481  	if fi.Mode() != subdirMode.Mode() {
   482  		t.Fatalf("wrong file mode: %v, expected: %v", fi.Mode(), subdirMode.Mode())
   483  	}
   484  }