github.com/bigcommerce/nomad@v0.9.3-bc/client/allocwatcher/alloc_watcher_unix_test.go (about)

     1  // +build !windows
     2  
     3  package allocwatcher
     4  
     5  import (
     6  	"archive/tar"
     7  	"bytes"
     8  	"context"
     9  	"fmt"
    10  	"io"
    11  	"io/ioutil"
    12  	"os"
    13  	"path/filepath"
    14  	"syscall"
    15  	"testing"
    16  
    17  	ctestutil "github.com/hashicorp/nomad/client/testutil"
    18  	"github.com/hashicorp/nomad/helper/testlog"
    19  )
    20  
    21  // TestPrevAlloc_StreamAllocDir_Ok asserts that streaming a tar to an alloc dir
    22  // works.
    23  func TestPrevAlloc_StreamAllocDir_Ok(t *testing.T) {
    24  	ctestutil.RequireRoot(t)
    25  	t.Parallel()
    26  	dir, err := ioutil.TempDir("", "")
    27  	if err != nil {
    28  		t.Fatalf("err: %v", err)
    29  	}
    30  	defer os.RemoveAll(dir)
    31  
    32  	// Create foo/
    33  	fooDir := filepath.Join(dir, "foo")
    34  	if err := os.Mkdir(fooDir, 0777); err != nil {
    35  		t.Fatalf("err: %v", err)
    36  	}
    37  
    38  	// Change ownership of foo/ to test #3702 (any non-root user is fine)
    39  	const uid, gid = 1, 1
    40  	if err := os.Chown(fooDir, uid, gid); err != nil {
    41  		t.Fatalf("err : %v", err)
    42  	}
    43  
    44  	dirInfo, err := os.Stat(fooDir)
    45  	if err != nil {
    46  		t.Fatalf("err: %v", err)
    47  	}
    48  
    49  	// Create foo/bar
    50  	f, err := os.Create(filepath.Join(fooDir, "bar"))
    51  	if err != nil {
    52  		t.Fatalf("err: %v", err)
    53  	}
    54  	if _, err := f.WriteString("123"); err != nil {
    55  		t.Fatalf("err: %v", err)
    56  	}
    57  	if err := f.Chmod(0644); err != nil {
    58  		t.Fatalf("err: %v", err)
    59  	}
    60  	fInfo, err := f.Stat()
    61  	if err != nil {
    62  		t.Fatalf("err: %v", err)
    63  	}
    64  	f.Close()
    65  
    66  	// Create foo/baz -> bar symlink
    67  	if err := os.Symlink("bar", filepath.Join(dir, "foo", "baz")); err != nil {
    68  		t.Fatalf("err: %v", err)
    69  	}
    70  	linkInfo, err := os.Lstat(filepath.Join(dir, "foo", "baz"))
    71  	if err != nil {
    72  		t.Fatalf("err: %v", err)
    73  	}
    74  
    75  	buf := new(bytes.Buffer)
    76  	tw := tar.NewWriter(buf)
    77  
    78  	walkFn := func(path string, fileInfo os.FileInfo, err error) error {
    79  		// Include the path of the file name relative to the alloc dir
    80  		// so that we can put the files in the right directories
    81  		link := ""
    82  		if fileInfo.Mode()&os.ModeSymlink != 0 {
    83  			target, err := os.Readlink(path)
    84  			if err != nil {
    85  				return fmt.Errorf("error reading symlink: %v", err)
    86  			}
    87  			link = target
    88  		}
    89  		hdr, err := tar.FileInfoHeader(fileInfo, link)
    90  		if err != nil {
    91  			return fmt.Errorf("error creating file header: %v", err)
    92  		}
    93  		hdr.Name = fileInfo.Name()
    94  		tw.WriteHeader(hdr)
    95  
    96  		// If it's a directory or symlink we just write the header into the tar
    97  		if fileInfo.IsDir() || (fileInfo.Mode()&os.ModeSymlink != 0) {
    98  			return nil
    99  		}
   100  
   101  		// Write the file into the archive
   102  		file, err := os.Open(path)
   103  		if err != nil {
   104  			return err
   105  		}
   106  		defer file.Close()
   107  
   108  		if _, err := io.Copy(tw, file); err != nil {
   109  			return err
   110  		}
   111  
   112  		return nil
   113  	}
   114  
   115  	if err := filepath.Walk(dir, walkFn); err != nil {
   116  		t.Fatalf("err: %v", err)
   117  	}
   118  	tw.Close()
   119  
   120  	dir1, err := ioutil.TempDir("", "nomadtest-")
   121  	if err != nil {
   122  		t.Fatalf("err: %v", err)
   123  	}
   124  	defer os.RemoveAll(dir1)
   125  
   126  	rc := ioutil.NopCloser(buf)
   127  	prevAlloc := &remotePrevAlloc{logger: testlog.HCLogger(t)}
   128  	if err := prevAlloc.streamAllocDir(context.Background(), rc, dir1); err != nil {
   129  		t.Fatalf("err: %v", err)
   130  	}
   131  
   132  	// Ensure foo is present
   133  	fi, err := os.Stat(filepath.Join(dir1, "foo"))
   134  	if err != nil {
   135  		t.Fatalf("err: %v", err)
   136  	}
   137  	if fi.Mode() != dirInfo.Mode() {
   138  		t.Fatalf("mode: %v", fi.Mode())
   139  	}
   140  	stat := fi.Sys().(*syscall.Stat_t)
   141  	if stat.Uid != uid || stat.Gid != gid {
   142  		t.Fatalf("foo/ has incorrect ownership: expected %d:%d found %d:%d",
   143  			uid, gid, stat.Uid, stat.Gid)
   144  	}
   145  
   146  	fi1, err := os.Stat(filepath.Join(dir1, "bar"))
   147  	if err != nil {
   148  		t.Fatalf("err: %v", err)
   149  	}
   150  	if fi1.Mode() != fInfo.Mode() {
   151  		t.Fatalf("mode: %v", fi1.Mode())
   152  	}
   153  
   154  	fi2, err := os.Lstat(filepath.Join(dir1, "baz"))
   155  	if err != nil {
   156  		t.Fatalf("err: %v", err)
   157  	}
   158  	if fi2.Mode() != linkInfo.Mode() {
   159  		t.Fatalf("mode: %v", fi2.Mode())
   160  	}
   161  }