Example #1
0
func TestTreeStoreWrite(t *testing.T) {
	if !sys.HasChrootCapability() {
		t.Skipf("chroot capability not available. Disabling test.")
	}

	dir, err := ioutil.TempDir("", tstprefix)
	if err != nil {
		t.Fatalf("error creating tempdir: %v", err)
	}
	defer os.RemoveAll(dir)
	s, err := NewStore(dir)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	key, err := treeStoreWriteACI(dir, s)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	id := "treestoreid01"

	// Ask the store to render the treestore
	_, err = s.treestore.Write(id, key, s)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	// Verify image Hash. Should be the same.
	_, err = s.treestore.Check(id)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
}
Example #2
0
// Because this function is executed by multicall in a different process, it is not possible to use errwrap to return errors
func extractTarCommand() error {
	if len(os.Args) != 5 {
		return fmt.Errorf("incorrect number of arguments. Usage: %s DIR {true|false} uidShift uidCount", multicallName)
	}
	if !sys.HasChrootCapability() {
		return fmt.Errorf("chroot capability not available.")
	}
	dir := os.Args[1]
	if !filepath.IsAbs(dir) {
		return fmt.Errorf("dir %s must be an absolute path", dir)
	}
	overwrite, err := strconv.ParseBool(os.Args[2])
	if err != nil {
		return fmt.Errorf("error parsing overwrite argument: %v", err)
	}

	us, err := strconv.ParseUint(os.Args[3], 10, 32)
	if err != nil {
		return fmt.Errorf("error parsing uidShift argument: %v", err)
	}
	uc, err := strconv.ParseUint(os.Args[4], 10, 32)
	if err != nil {
		return fmt.Errorf("error parsing uidCount argument: %v", err)
	}

	uidRange := &user.UidRange{Shift: uint32(us), Count: uint32(uc)}

	if err := syscall.Chroot(dir); err != nil {
		return fmt.Errorf("failed to chroot in %s: %v", dir, err)
	}
	if err := syscall.Chdir("/"); err != nil {
		return fmt.Errorf("failed to chdir: %v", err)
	}
	fileMapFile := os.NewFile(uintptr(fileMapFdNum), "fileMap")

	fileMap := map[string]struct{}{}
	if err := json.NewDecoder(fileMapFile).Decode(&fileMap); err != nil {
		return fmt.Errorf("error decoding fileMap: %v", err)
	}
	editor, err := NewUidShiftingFilePermEditor(uidRange)
	if err != nil {
		return fmt.Errorf("error determining current user: %v", err)
	}
	if err := ExtractTarInsecure(tar.NewReader(os.Stdin), "/", overwrite, fileMap, editor); err != nil {
		return fmt.Errorf("error extracting tar: %v", err)
	}

	// flush remaining bytes
	io.Copy(ioutil.Discard, os.Stdin)

	return nil
}
Example #3
0
func TestTreeStoreRemove(t *testing.T) {
	if !sys.HasChrootCapability() {
		t.Skipf("chroot capability not available. Disabling test.")
	}

	dir, err := ioutil.TempDir("", tstprefix)
	if err != nil {
		t.Fatalf("error creating tempdir: %v", err)
	}
	defer os.RemoveAll(dir)

	s, err := imagestore.NewStore(dir)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	ts, err := NewStore(dir, s)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	key, err := testStoreWriteACI(dir, s)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	id := "treestoreid01"

	// Test non existent dir
	err = ts.remove(id)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	// Test rendered tree
	_, err = ts.render(id, key)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	err = ts.remove(id)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
}
Example #4
0
func extractTarCommand() error {
	if len(os.Args) != 3 {
		return fmt.Errorf("incorrect number of arguments. Usage: %s DIR {true|false}", multicallName)
	}
	if !sys.HasChrootCapability() {
		return fmt.Errorf("chroot capability not available.")
	}
	dir := os.Args[1]
	if !filepath.IsAbs(dir) {
		return fmt.Errorf("dir %s must be an absolute path", dir)
	}
	overwrite, err := strconv.ParseBool(os.Args[2])
	if err != nil {
		return fmt.Errorf("error parsing overwrite argument: %v", err)
	}

	if err := syscall.Chroot(dir); err != nil {
		return fmt.Errorf("failed to chroot in %s: %v", dir, err)
	}
	if err := syscall.Chdir("/"); err != nil {
		return fmt.Errorf("failed to chdir: %v", err)
	}
	fileMapFile := os.NewFile(uintptr(fileMapFdNum), "fileMap")

	fileMap := map[string]struct{}{}
	if err := json.NewDecoder(fileMapFile).Decode(&fileMap); err != nil {
		return fmt.Errorf("error decoding fileMap: %v", err)
	}
	if err := extractTar(tar.NewReader(os.Stdin), overwrite, fileMap); err != nil {
		return fmt.Errorf("error extracting tar: %v", err)
	}

	// flush remaining bytes
	io.Copy(ioutil.Discard, os.Stdin)

	return nil
}
Example #5
0
func TestTreeStore(t *testing.T) {
	if !sys.HasChrootCapability() {
		t.Skipf("chroot capability not available. Disabling test.")
	}

	dir, err := ioutil.TempDir("", tstprefix)
	if err != nil {
		t.Fatalf("error creating tempdir: %v", err)
	}
	defer os.RemoveAll(dir)
	s, err := NewStore(dir)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	imj := `
		{
		    "acKind": "ImageManifest",
		    "acVersion": "0.7.1",
		    "name": "example.com/test01"
		}
	`

	entries := []*aci.ACIEntry{
		// An empty dir
		{
			Header: &tar.Header{
				Name:     "rootfs/a",
				Typeflag: tar.TypeDir,
			},
		},
		{
			Contents: "hello",
			Header: &tar.Header{
				Name: "hello.txt",
				Size: 5,
			},
		},
		{
			Header: &tar.Header{
				Name:     "rootfs/link.txt",
				Linkname: "rootfs/hello.txt",
				Typeflag: tar.TypeSymlink,
			},
		},
		// dangling symlink
		{
			Header: &tar.Header{
				Name:     "rootfs/link2.txt",
				Linkname: "rootfs/missingfile.txt",
				Typeflag: tar.TypeSymlink,
			},
		},
		{
			Header: &tar.Header{
				Name:     "rootfs/fifo",
				Typeflag: tar.TypeFifo,
			},
		},
	}
	aci, err := aci.NewACI(dir, imj, entries)
	if err != nil {
		t.Fatalf("error creating test tar: %v", err)
	}
	defer aci.Close()

	// Rewind the ACI
	if _, err := aci.Seek(0, 0); err != nil {
		t.Fatalf("unexpected error %v", err)
	}

	// Import the new ACI
	key, err := s.WriteACI(aci, false)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	// Ask the store to render the treestore
	id, err := s.RenderTreeStore(key, false)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	// Verify image Hash. Should be the same.
	err = s.CheckTreeStore(id)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	// Change a file permission
	rootfs := s.GetTreeStoreRootFS(id)
	err = os.Chmod(filepath.Join(rootfs, "a"), 0600)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	// Verify image Hash. Should be different
	err = s.CheckTreeStore(id)
	if err == nil {
		t.Errorf("expected non-nil error!")
	}

	// rebuild the tree
	prevID := id
	id, err = s.RenderTreeStore(key, true)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	if id != prevID {
		t.Fatalf("unexpected different IDs. prevID: %s, id: %s", prevID, id)
	}

	// Add a file
	rootfs = s.GetTreeStoreRootFS(id)
	err = ioutil.WriteFile(filepath.Join(rootfs, "newfile"), []byte("newfile"), 0644)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	// Verify image Hash. Should be different
	err = s.CheckTreeStore(id)
	if err == nil {
		t.Errorf("expected non-nil error!")
	}
}
Example #6
0
func TestExtractTarTimes(t *testing.T) {
	if !sys.HasChrootCapability() {
		t.Skipf("chroot capability not available. Disabling test.")
	}

	// Do not set ns as tar has second precision
	time1 := time.Unix(100000, 0)
	time2 := time.Unix(200000, 0)
	time3 := time.Unix(300000, 0)
	entries := []*testTarEntry{
		{
			header: &tar.Header{
				Name:     "folder/",
				Typeflag: tar.TypeDir,
				Mode:     int64(0747),
				ModTime:  time1,
			},
		},
		{
			contents: "foo",
			header: &tar.Header{
				Name:    "folder/foo.txt",
				Size:    3,
				ModTime: time2,
			},
		},
		{
			header: &tar.Header{
				Name:     "folder/symlink.txt",
				Typeflag: tar.TypeSymlink,
				Linkname: "folder/foo.txt",
				ModTime:  time3,
			},
		},
	}

	testTarPath, err := newTestTar(entries)
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}
	defer os.Remove(testTarPath)
	containerTar, err := os.Open(testTarPath)
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}
	defer containerTar.Close()
	tmpdir, err := ioutil.TempDir("", "rkt-temp-dir")
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}
	os.RemoveAll(tmpdir)
	err = os.MkdirAll(tmpdir, 0755)
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}
	err = ExtractTar(containerTar, tmpdir, false, nil)
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}
	err = checkTime(filepath.Join(tmpdir, "folder/"), time1)
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}
	err = checkTime(filepath.Join(tmpdir, "folder/foo.txt"), time2)
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}

	//Check only (by now) on linux
	if runtime.GOOS == "linux" {
		err = checkTime(filepath.Join(tmpdir, "folder/symlink.txt"), time3)
		if err != nil {
			t.Errorf("unexpected error: %v", err)
		}
	}
}
Example #7
0
func TestExtractTarOverwrite(t *testing.T) {
	if !sys.HasChrootCapability() {
		t.Skipf("chroot capability not available. Disabling test.")
	}

	tmpdir, err := ioutil.TempDir("", "rkt-temp-dir")
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	defer os.RemoveAll(tmpdir)

	entries := []*testTarEntry{
		{
			contents: "hello",
			header: &tar.Header{
				Name: "hello.txt",
				Size: 5,
			},
		},
		{
			header: &tar.Header{
				Name:     "afolder",
				Typeflag: tar.TypeDir,
			},
		},
		{
			contents: "hello",
			header: &tar.Header{
				Name: "afolder/hello.txt",
				Size: 5,
			},
		},
		{
			contents: "hello",
			header: &tar.Header{
				Name: "afile",
				Size: 5,
			},
		},
		{
			header: &tar.Header{
				Name:     "folder01",
				Typeflag: tar.TypeDir,
			},
		},
		{
			contents: "hello",
			header: &tar.Header{
				Name: "folder01/file01",
				Size: 5,
			},
		},
		{
			contents: "hello",
			header: &tar.Header{
				Name: "filesymlinked",
				Size: 5,
			},
		},
		{
			header: &tar.Header{
				Name:     "linktofile",
				Linkname: "filesymlinked",
				Typeflag: tar.TypeSymlink,
			},
		},

		{
			header: &tar.Header{
				Name:     "dirsymlinked",
				Typeflag: tar.TypeDir,
			},
		},
		{
			header: &tar.Header{
				Name:     "linktodir",
				Linkname: "dirsymlinked",
				Typeflag: tar.TypeSymlink,
			},
		},
	}

	testTarPath, err := newTestTar(entries)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	defer os.Remove(testTarPath)
	containerTar1, err := os.Open(testTarPath)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	defer containerTar1.Close()
	err = ExtractTar(containerTar1, tmpdir, false, nil)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	// Now overwrite:
	// a file with a new file
	// a dir with a file
	entries = []*testTarEntry{
		{
			contents: "newhello",
			header: &tar.Header{
				Name: "hello.txt",
				Size: 8,
			},
		},
		// Now this is a file
		{
			contents: "nowafile",
			header: &tar.Header{
				Name:     "afolder",
				Typeflag: tar.TypeReg,
				Size:     8,
			},
		},
		// Now this is a dir
		{
			header: &tar.Header{
				Name:     "afile",
				Typeflag: tar.TypeDir,
			},
		},
		// Overwrite symlink to a file with a regular file
		// the linked file shouldn't be removed
		{
			contents: "filereplacingsymlink",
			header: &tar.Header{
				Name:     "linktofile",
				Typeflag: tar.TypeReg,
				Size:     20,
			},
		},
		// Overwrite symlink to a dir with a regular file
		// the linked directory and all its contents shouldn't be
		// removed
		{
			contents: "filereplacingsymlink",
			header: &tar.Header{
				Name:     "linktodir",
				Typeflag: tar.TypeReg,
				Size:     20,
			},
		},
		// folder01 already exists and shouldn't be removed (keeping folder01/file01)
		{
			header: &tar.Header{
				Name:     "folder01",
				Typeflag: tar.TypeDir,
				Mode:     int64(0755),
			},
		},
		{
			contents: "hello",
			header: &tar.Header{
				Name: "folder01/file02",
				Size: 5,
				Mode: int64(0644),
			},
		},
	}
	testTarPath, err = newTestTar(entries)
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}
	defer os.Remove(testTarPath)
	containerTar2, err := os.Open(testTarPath)
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}
	defer containerTar2.Close()
	err = ExtractTar(containerTar2, tmpdir, true, nil)

	expectedFiles := []*fileInfo{
		&fileInfo{path: "hello.txt", typeflag: tar.TypeReg, size: 8, contents: "newhello"},
		&fileInfo{path: "linktofile", typeflag: tar.TypeReg, size: 20},
		&fileInfo{path: "linktodir", typeflag: tar.TypeReg, size: 20},
		&fileInfo{path: "afolder", typeflag: tar.TypeReg, size: 8},
		&fileInfo{path: "dirsymlinked", typeflag: tar.TypeDir},
		&fileInfo{path: "afile", typeflag: tar.TypeDir},
		&fileInfo{path: "filesymlinked", typeflag: tar.TypeReg, size: 5},
		&fileInfo{path: "folder01", typeflag: tar.TypeDir},
		&fileInfo{path: "folder01/file01", typeflag: tar.TypeReg, size: 5},
		&fileInfo{path: "folder01/file02", typeflag: tar.TypeReg, size: 5},
	}

	err = checkExpectedFiles(tmpdir, fileInfoSliceToMap(expectedFiles))
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}
}
Example #8
0
func TestExtractTarPWL(t *testing.T) {
	if !sys.HasChrootCapability() {
		t.Skipf("chroot capability not available. Disabling test.")
	}
	entries := []*testTarEntry{
		{
			header: &tar.Header{
				Name:     "folder/",
				Typeflag: tar.TypeDir,
				Mode:     int64(0747),
			},
		},
		{
			contents: "foo",
			header: &tar.Header{
				Name: "folder/foo.txt",
				Size: 3,
			},
		},
		{
			contents: "bar",
			header: &tar.Header{
				Name: "folder/bar.txt",
				Size: 3,
			},
		},
		{
			header: &tar.Header{
				Name:     "folder/symlink.txt",
				Typeflag: tar.TypeSymlink,
				Linkname: "folder/foo.txt",
			},
		},
	}
	testTarPath, err := newTestTar(entries)
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}
	defer os.Remove(testTarPath)
	containerTar, err := os.Open(testTarPath)
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}
	defer containerTar.Close()
	tmpdir, err := ioutil.TempDir("", "rkt-temp-dir")
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}
	defer os.RemoveAll(tmpdir)

	pwl := make(PathWhitelistMap)
	pwl["folder/foo.txt"] = struct{}{}
	err = ExtractTar(containerTar, tmpdir, false, pwl)
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}
	matches, err := filepath.Glob(filepath.Join(tmpdir, "folder/*.txt"))
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}
	if len(matches) != 1 {
		t.Errorf("unexpected number of files found: %d, wanted 1", len(matches))
	}
}
Example #9
0
func TestExtractTarFolders(t *testing.T) {
	if !sys.HasChrootCapability() {
		t.Skipf("chroot capability not available. Disabling test.")
	}

	entries := []*testTarEntry{
		{
			contents: "foo",
			header: &tar.Header{
				Name: "deep/folder/foo.txt",
				Size: 3,
			},
		},
		{
			header: &tar.Header{
				Name:     "deep/folder/",
				Typeflag: tar.TypeDir,
				Mode:     int64(0747),
			},
		},
		{
			contents: "bar",
			header: &tar.Header{
				Name: "deep/folder/bar.txt",
				Size: 3,
			},
		},
		{
			header: &tar.Header{
				Name:     "deep/folder2/symlink.txt",
				Typeflag: tar.TypeSymlink,
				Linkname: "deep/folder/foo.txt",
			},
		},
		{
			header: &tar.Header{
				Name:     "deep/folder2/",
				Typeflag: tar.TypeDir,
				Mode:     int64(0747),
			},
		},
		{
			contents: "bar",
			header: &tar.Header{
				Name: "deep/folder2/bar.txt",
				Size: 3,
			},
		},
		{
			header: &tar.Header{
				Name:     "deep/deep/folder",
				Typeflag: tar.TypeDir,
				Mode:     int64(0755),
			},
		},
		{
			header: &tar.Header{
				Name:     "deep/deep/",
				Typeflag: tar.TypeDir,
				Mode:     int64(0747),
			},
		},
	}

	testTarPath, err := newTestTar(entries)
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}
	defer os.Remove(testTarPath)
	containerTar, err := os.Open(testTarPath)
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}
	defer containerTar.Close()
	tmpdir, err := ioutil.TempDir("", "rkt-temp-dir")
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}
	os.RemoveAll(tmpdir)
	err = os.MkdirAll(tmpdir, 0755)
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}
	defer os.RemoveAll(tmpdir)
	err = ExtractTar(containerTar, tmpdir, false, nil)
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}
	matches, err := filepath.Glob(filepath.Join(tmpdir, "deep/folder/*.txt"))
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}
	if len(matches) != 2 {
		t.Errorf("unexpected number of files found: %d, wanted 2", len(matches))
	}
	matches, err = filepath.Glob(filepath.Join(tmpdir, "deep/folder2/*.txt"))
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	}
	if len(matches) != 2 {
		t.Errorf("unexpected number of files found: %d, wanted 2", len(matches))
	}

	dirInfo, err := os.Lstat(filepath.Join(tmpdir, "deep/folder"))
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	} else if dirInfo.Mode().Perm() != os.FileMode(0747) {
		t.Errorf("unexpected dir mode: %s", dirInfo.Mode())
	}
	dirInfo, err = os.Lstat(filepath.Join(tmpdir, "deep/deep"))
	if err != nil {
		t.Errorf("unexpected error: %v", err)
	} else if dirInfo.Mode().Perm() != os.FileMode(0747) {
		t.Errorf("unexpected dir mode: %s", dirInfo.Mode())
	}
}
Example #10
0
File: tar_test.go Project: nak3/rkt
func TestExtractTarHardLink(t *testing.T) {
	if !sys.HasChrootCapability() {
		t.Skipf("chroot capability not available. Disabling test.")
	}
	testExtractTarHardLink(t, extractTarHelper)
}