Skip to content

Commit

Permalink
Merge pull request #2687 from mmickan/issue-2685
Browse files Browse the repository at this point in the history
Include symlinks in snapshots when migrating disks
  • Loading branch information
dadgar committed Jun 8, 2017
2 parents 1d61afc + e418b3e commit dd9e84a
Show file tree
Hide file tree
Showing 4 changed files with 63 additions and 17 deletions.
19 changes: 11 additions & 8 deletions client/allocdir/alloc_dir.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,26 +118,29 @@ func (d *AllocDir) Snapshot(w io.Writer) error {
defer tw.Close()

walkFn := func(path string, fileInfo os.FileInfo, err error) error {
// Ignore if the file is a symlink
if fileInfo.Mode() == os.ModeSymlink {
return nil
}

// Include the path of the file name relative to the alloc dir
// so that we can put the files in the right directories
relPath, err := filepath.Rel(d.AllocDir, path)
if err != nil {
return err
}
hdr, err := tar.FileInfoHeader(fileInfo, "")
link := ""
if fileInfo.Mode()&os.ModeSymlink != 0 {
target, err := os.Readlink(path)
if err != nil {
return fmt.Errorf("error reading symlink: %v", err)
}
link = target
}
hdr, err := tar.FileInfoHeader(fileInfo, link)
if err != nil {
return fmt.Errorf("error creating file header: %v", err)
}
hdr.Name = relPath
tw.WriteHeader(hdr)

// If it's a directory we just write the header into the tar
if fileInfo.IsDir() {
// If it's a directory or symlink we just write the header into the tar
if fileInfo.IsDir() || (fileInfo.Mode()&os.ModeSymlink != 0) {
return nil
}

Expand Down
20 changes: 19 additions & 1 deletion client/allocdir/alloc_dir_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,11 +166,23 @@ func TestAllocDir_Snapshot(t *testing.T) {
t.Fatalf("Couldn't write file to shared directory: %v", err)
}

// Write a symlink to the shared dir
link := "qux"
if err := os.Symlink("foo", filepath.Join(d.SharedDir, "data", link)); err != nil {
t.Fatalf("Couldn't write symlink to shared directory: %v", err)
}

// Write a file to the task local
exp = []byte{'b', 'a', 'r'}
file1 := "lol"
if err := ioutil.WriteFile(filepath.Join(td1.LocalDir, file1), exp, 0666); err != nil {
t.Fatalf("couldn't write to task local directory: %v", err)
t.Fatalf("couldn't write file to task local directory: %v", err)
}

// Write a symlink to the task local
link1 := "baz"
if err := os.Symlink("bar", filepath.Join(td1.LocalDir, link1)); err != nil {
t.Fatalf("couldn't write symlink to task local dirctory :%v", err)
}

var b bytes.Buffer
Expand All @@ -180,6 +192,7 @@ func TestAllocDir_Snapshot(t *testing.T) {

tr := tar.NewReader(&b)
var files []string
var links []string
for {
hdr, err := tr.Next()
if err != nil && err != io.EOF {
Expand All @@ -190,12 +203,17 @@ func TestAllocDir_Snapshot(t *testing.T) {
}
if hdr.Typeflag == tar.TypeReg {
files = append(files, hdr.FileInfo().Name())
} else if hdr.Typeflag == tar.TypeSymlink {
links = append(links, hdr.FileInfo().Name())
}
}

if len(files) != 2 {
t.Fatalf("bad files: %#v", files)
}
if len(links) != 2 {
t.Fatalf("bad links: %#v", links)
}
}

func TestAllocDir_Move(t *testing.T) {
Expand Down
7 changes: 7 additions & 0 deletions client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -1851,6 +1851,13 @@ func (c *Client) unarchiveAllocDir(resp io.ReadCloser, allocID string, pathToAll
os.MkdirAll(filepath.Join(pathToAllocDir, hdr.Name), os.FileMode(hdr.Mode))
continue
}
// If the header is for a symlink we create the symlink
if hdr.Typeflag == tar.TypeSymlink {
if err = os.Symlink(hdr.Linkname, filepath.Join(pathToAllocDir, hdr.Name)); err != nil {
c.logger.Printf("[ERR] client: error creating symlink: %v", err)
}
continue
}
// If the header is a file, we write to a file
if hdr.Typeflag == tar.TypeReg {
f, err := os.Create(filepath.Join(pathToAllocDir, hdr.Name))
Expand Down
34 changes: 26 additions & 8 deletions client/client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -939,27 +939,37 @@ func TestClient_UnarchiveAllocDir(t *testing.T) {
t.Fatalf("err: %v", err)
}
f.Close()
if err := os.Symlink("bar", filepath.Join(dir, "foo", "baz")); err != nil {
t.Fatalf("err: %v", err)
}
linkInfo, err := os.Lstat(filepath.Join(dir, "foo", "baz"))
if err != nil {
t.Fatalf("err: %v", err)
}

buf := new(bytes.Buffer)
tw := tar.NewWriter(buf)

walkFn := func(path string, fileInfo os.FileInfo, err error) error {
// Ignore if the file is a symlink
if fileInfo.Mode() == os.ModeSymlink {
return nil
}

// Include the path of the file name relative to the alloc dir
// so that we can put the files in the right directories
hdr, err := tar.FileInfoHeader(fileInfo, "")
link := ""
if fileInfo.Mode()&os.ModeSymlink != 0 {
target, err := os.Readlink(path)
if err != nil {
return fmt.Errorf("error reading symlink: %v", err)
}
link = target
}
hdr, err := tar.FileInfoHeader(fileInfo, link)
if err != nil {
return fmt.Errorf("error creating file header: %v", err)
}
hdr.Name = fileInfo.Name()
tw.WriteHeader(hdr)

// If it's a directory we just write the header into the tar
if fileInfo.IsDir() {
// If it's a directory or symlink we just write the header into the tar
if fileInfo.IsDir() || (fileInfo.Mode()&os.ModeSymlink != 0) {
return nil
}

Expand Down Expand Up @@ -1016,4 +1026,12 @@ func TestClient_UnarchiveAllocDir(t *testing.T) {
if fi1.Mode() != fInfo.Mode() {
t.Fatalf("mode: %v", fi1.Mode())
}

fi2, err := os.Lstat(filepath.Join(dir1, "baz"))
if err != nil {
t.Fatalf("err: %v", err)
}
if fi2.Mode() != linkInfo.Mode() {
t.Fatalf("mode: %v", fi2.Mode())
}
}

0 comments on commit dd9e84a

Please sign in to comment.