github.com/iqoqo/nomad@v0.11.3-0.20200911112621-d7021c74d101/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  		// filepath.Walk passes in an error
    80  		if err != nil {
    81  			return fmt.Errorf("error from filepath.Walk(): %s", err)
    82  		}
    83  		// Include the path of the file name relative to the alloc dir
    84  		// so that we can put the files in the right directories
    85  		link := ""
    86  		if fileInfo.Mode()&os.ModeSymlink != 0 {
    87  			target, err := os.Readlink(path)
    88  			if err != nil {
    89  				return fmt.Errorf("error reading symlink: %v", err)
    90  			}
    91  			link = target
    92  		}
    93  		hdr, err := tar.FileInfoHeader(fileInfo, link)
    94  		if err != nil {
    95  			return fmt.Errorf("error creating file header: %v", err)
    96  		}
    97  		hdr.Name = fileInfo.Name()
    98  		tw.WriteHeader(hdr)
    99  
   100  		// If it's a directory or symlink we just write the header into the tar
   101  		if fileInfo.IsDir() || (fileInfo.Mode()&os.ModeSymlink != 0) {
   102  			return nil
   103  		}
   104  
   105  		// Write the file into the archive
   106  		file, err := os.Open(path)
   107  		if err != nil {
   108  			return err
   109  		}
   110  		defer file.Close()
   111  
   112  		if _, err := io.Copy(tw, file); err != nil {
   113  			return err
   114  		}
   115  
   116  		return nil
   117  	}
   118  
   119  	if err := filepath.Walk(dir, walkFn); err != nil {
   120  		t.Fatalf("err: %v", err)
   121  	}
   122  	tw.Close()
   123  
   124  	dir1, err := ioutil.TempDir("", "nomadtest-")
   125  	if err != nil {
   126  		t.Fatalf("err: %v", err)
   127  	}
   128  	defer os.RemoveAll(dir1)
   129  
   130  	rc := ioutil.NopCloser(buf)
   131  	prevAlloc := &remotePrevAlloc{logger: testlog.HCLogger(t)}
   132  	if err := prevAlloc.streamAllocDir(context.Background(), rc, dir1); err != nil {
   133  		t.Fatalf("err: %v", err)
   134  	}
   135  
   136  	// Ensure foo is present
   137  	fi, err := os.Stat(filepath.Join(dir1, "foo"))
   138  	if err != nil {
   139  		t.Fatalf("err: %v", err)
   140  	}
   141  	if fi.Mode() != dirInfo.Mode() {
   142  		t.Fatalf("mode: %v", fi.Mode())
   143  	}
   144  	stat := fi.Sys().(*syscall.Stat_t)
   145  	if stat.Uid != uid || stat.Gid != gid {
   146  		t.Fatalf("foo/ has incorrect ownership: expected %d:%d found %d:%d",
   147  			uid, gid, stat.Uid, stat.Gid)
   148  	}
   149  
   150  	fi1, err := os.Stat(filepath.Join(dir1, "bar"))
   151  	if err != nil {
   152  		t.Fatalf("err: %v", err)
   153  	}
   154  	if fi1.Mode() != fInfo.Mode() {
   155  		t.Fatalf("mode: %v", fi1.Mode())
   156  	}
   157  
   158  	fi2, err := os.Lstat(filepath.Join(dir1, "baz"))
   159  	if err != nil {
   160  		t.Fatalf("err: %v", err)
   161  	}
   162  	if fi2.Mode() != linkInfo.Mode() {
   163  		t.Fatalf("mode: %v", fi2.Mode())
   164  	}
   165  }