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 }