github.com/olljanat/moby@v1.13.1/pkg/idtools/idtools_unix_test.go (about)

     1  // +build !windows
     2  
     3  package idtools
     4  
     5  import (
     6  	"fmt"
     7  	"io/ioutil"
     8  	"os"
     9  	"path/filepath"
    10  	"syscall"
    11  	"testing"
    12  )
    13  
    14  type node struct {
    15  	uid int
    16  	gid int
    17  }
    18  
    19  func TestMkdirAllAs(t *testing.T) {
    20  	dirName, err := ioutil.TempDir("", "mkdirall")
    21  	if err != nil {
    22  		t.Fatalf("Couldn't create temp dir: %v", err)
    23  	}
    24  	defer os.RemoveAll(dirName)
    25  
    26  	testTree := map[string]node{
    27  		"usr":              {0, 0},
    28  		"usr/bin":          {0, 0},
    29  		"lib":              {33, 33},
    30  		"lib/x86_64":       {45, 45},
    31  		"lib/x86_64/share": {1, 1},
    32  	}
    33  
    34  	if err := buildTree(dirName, testTree); err != nil {
    35  		t.Fatal(err)
    36  	}
    37  
    38  	// test adding a directory to a pre-existing dir; only the new dir is owned by the uid/gid
    39  	if err := MkdirAllAs(filepath.Join(dirName, "usr", "share"), 0755, 99, 99); err != nil {
    40  		t.Fatal(err)
    41  	}
    42  	testTree["usr/share"] = node{99, 99}
    43  	verifyTree, err := readTree(dirName, "")
    44  	if err != nil {
    45  		t.Fatal(err)
    46  	}
    47  	if err := compareTrees(testTree, verifyTree); err != nil {
    48  		t.Fatal(err)
    49  	}
    50  
    51  	// test 2-deep new directories--both should be owned by the uid/gid pair
    52  	if err := MkdirAllAs(filepath.Join(dirName, "lib", "some", "other"), 0755, 101, 101); err != nil {
    53  		t.Fatal(err)
    54  	}
    55  	testTree["lib/some"] = node{101, 101}
    56  	testTree["lib/some/other"] = node{101, 101}
    57  	verifyTree, err = readTree(dirName, "")
    58  	if err != nil {
    59  		t.Fatal(err)
    60  	}
    61  	if err := compareTrees(testTree, verifyTree); err != nil {
    62  		t.Fatal(err)
    63  	}
    64  
    65  	// test a directory that already exists; should be chowned, but nothing else
    66  	if err := MkdirAllAs(filepath.Join(dirName, "usr"), 0755, 102, 102); err != nil {
    67  		t.Fatal(err)
    68  	}
    69  	testTree["usr"] = node{102, 102}
    70  	verifyTree, err = readTree(dirName, "")
    71  	if err != nil {
    72  		t.Fatal(err)
    73  	}
    74  	if err := compareTrees(testTree, verifyTree); err != nil {
    75  		t.Fatal(err)
    76  	}
    77  }
    78  
    79  func TestMkdirAllNewAs(t *testing.T) {
    80  
    81  	dirName, err := ioutil.TempDir("", "mkdirnew")
    82  	if err != nil {
    83  		t.Fatalf("Couldn't create temp dir: %v", err)
    84  	}
    85  	defer os.RemoveAll(dirName)
    86  
    87  	testTree := map[string]node{
    88  		"usr":              {0, 0},
    89  		"usr/bin":          {0, 0},
    90  		"lib":              {33, 33},
    91  		"lib/x86_64":       {45, 45},
    92  		"lib/x86_64/share": {1, 1},
    93  	}
    94  
    95  	if err := buildTree(dirName, testTree); err != nil {
    96  		t.Fatal(err)
    97  	}
    98  
    99  	// test adding a directory to a pre-existing dir; only the new dir is owned by the uid/gid
   100  	if err := MkdirAllNewAs(filepath.Join(dirName, "usr", "share"), 0755, 99, 99); err != nil {
   101  		t.Fatal(err)
   102  	}
   103  	testTree["usr/share"] = node{99, 99}
   104  	verifyTree, err := readTree(dirName, "")
   105  	if err != nil {
   106  		t.Fatal(err)
   107  	}
   108  	if err := compareTrees(testTree, verifyTree); err != nil {
   109  		t.Fatal(err)
   110  	}
   111  
   112  	// test 2-deep new directories--both should be owned by the uid/gid pair
   113  	if err := MkdirAllNewAs(filepath.Join(dirName, "lib", "some", "other"), 0755, 101, 101); err != nil {
   114  		t.Fatal(err)
   115  	}
   116  	testTree["lib/some"] = node{101, 101}
   117  	testTree["lib/some/other"] = node{101, 101}
   118  	verifyTree, err = readTree(dirName, "")
   119  	if err != nil {
   120  		t.Fatal(err)
   121  	}
   122  	if err := compareTrees(testTree, verifyTree); err != nil {
   123  		t.Fatal(err)
   124  	}
   125  
   126  	// test a directory that already exists; should NOT be chowned
   127  	if err := MkdirAllNewAs(filepath.Join(dirName, "usr"), 0755, 102, 102); err != nil {
   128  		t.Fatal(err)
   129  	}
   130  	verifyTree, err = readTree(dirName, "")
   131  	if err != nil {
   132  		t.Fatal(err)
   133  	}
   134  	if err := compareTrees(testTree, verifyTree); err != nil {
   135  		t.Fatal(err)
   136  	}
   137  }
   138  
   139  func TestMkdirAs(t *testing.T) {
   140  
   141  	dirName, err := ioutil.TempDir("", "mkdir")
   142  	if err != nil {
   143  		t.Fatalf("Couldn't create temp dir: %v", err)
   144  	}
   145  	defer os.RemoveAll(dirName)
   146  
   147  	testTree := map[string]node{
   148  		"usr": {0, 0},
   149  	}
   150  	if err := buildTree(dirName, testTree); err != nil {
   151  		t.Fatal(err)
   152  	}
   153  
   154  	// test a directory that already exists; should just chown to the requested uid/gid
   155  	if err := MkdirAs(filepath.Join(dirName, "usr"), 0755, 99, 99); err != nil {
   156  		t.Fatal(err)
   157  	}
   158  	testTree["usr"] = node{99, 99}
   159  	verifyTree, err := readTree(dirName, "")
   160  	if err != nil {
   161  		t.Fatal(err)
   162  	}
   163  	if err := compareTrees(testTree, verifyTree); err != nil {
   164  		t.Fatal(err)
   165  	}
   166  
   167  	// create a subdir under a dir which doesn't exist--should fail
   168  	if err := MkdirAs(filepath.Join(dirName, "usr", "bin", "subdir"), 0755, 102, 102); err == nil {
   169  		t.Fatalf("Trying to create a directory with Mkdir where the parent doesn't exist should have failed")
   170  	}
   171  
   172  	// create a subdir under an existing dir; should only change the ownership of the new subdir
   173  	if err := MkdirAs(filepath.Join(dirName, "usr", "bin"), 0755, 102, 102); err != nil {
   174  		t.Fatal(err)
   175  	}
   176  	testTree["usr/bin"] = node{102, 102}
   177  	verifyTree, err = readTree(dirName, "")
   178  	if err != nil {
   179  		t.Fatal(err)
   180  	}
   181  	if err := compareTrees(testTree, verifyTree); err != nil {
   182  		t.Fatal(err)
   183  	}
   184  }
   185  
   186  func buildTree(base string, tree map[string]node) error {
   187  	for path, node := range tree {
   188  		fullPath := filepath.Join(base, path)
   189  		if err := os.MkdirAll(fullPath, 0755); err != nil {
   190  			return fmt.Errorf("Couldn't create path: %s; error: %v", fullPath, err)
   191  		}
   192  		if err := os.Chown(fullPath, node.uid, node.gid); err != nil {
   193  			return fmt.Errorf("Couldn't chown path: %s; error: %v", fullPath, err)
   194  		}
   195  	}
   196  	return nil
   197  }
   198  
   199  func readTree(base, root string) (map[string]node, error) {
   200  	tree := make(map[string]node)
   201  
   202  	dirInfos, err := ioutil.ReadDir(base)
   203  	if err != nil {
   204  		return nil, fmt.Errorf("Couldn't read directory entries for %q: %v", base, err)
   205  	}
   206  
   207  	for _, info := range dirInfos {
   208  		s := &syscall.Stat_t{}
   209  		if err := syscall.Stat(filepath.Join(base, info.Name()), s); err != nil {
   210  			return nil, fmt.Errorf("Can't stat file %q: %v", filepath.Join(base, info.Name()), err)
   211  		}
   212  		tree[filepath.Join(root, info.Name())] = node{int(s.Uid), int(s.Gid)}
   213  		if info.IsDir() {
   214  			// read the subdirectory
   215  			subtree, err := readTree(filepath.Join(base, info.Name()), filepath.Join(root, info.Name()))
   216  			if err != nil {
   217  				return nil, err
   218  			}
   219  			for path, nodeinfo := range subtree {
   220  				tree[path] = nodeinfo
   221  			}
   222  		}
   223  	}
   224  	return tree, nil
   225  }
   226  
   227  func compareTrees(left, right map[string]node) error {
   228  	if len(left) != len(right) {
   229  		return fmt.Errorf("Trees aren't the same size")
   230  	}
   231  	for path, nodeLeft := range left {
   232  		if nodeRight, ok := right[path]; ok {
   233  			if nodeRight.uid != nodeLeft.uid || nodeRight.gid != nodeLeft.gid {
   234  				// mismatch
   235  				return fmt.Errorf("mismatched ownership for %q: expected: %d:%d, got: %d:%d", path,
   236  					nodeLeft.uid, nodeLeft.gid, nodeRight.uid, nodeRight.gid)
   237  			}
   238  			continue
   239  		}
   240  		return fmt.Errorf("right tree didn't contain path %q", path)
   241  	}
   242  	return nil
   243  }
   244  
   245  func TestParseSubidFileWithNewlinesAndComments(t *testing.T) {
   246  	tmpDir, err := ioutil.TempDir("", "parsesubid")
   247  	if err != nil {
   248  		t.Fatal(err)
   249  	}
   250  	fnamePath := filepath.Join(tmpDir, "testsubuid")
   251  	fcontent := `tss:100000:65536
   252  # empty default subuid/subgid file
   253  
   254  dockremap:231072:65536`
   255  	if err := ioutil.WriteFile(fnamePath, []byte(fcontent), 0644); err != nil {
   256  		t.Fatal(err)
   257  	}
   258  	ranges, err := parseSubidFile(fnamePath, "dockremap")
   259  	if err != nil {
   260  		t.Fatal(err)
   261  	}
   262  	if len(ranges) != 1 {
   263  		t.Fatalf("wanted 1 element in ranges, got %d instead", len(ranges))
   264  	}
   265  	if ranges[0].Start != 231072 {
   266  		t.Fatalf("wanted 231072, got %d instead", ranges[0].Start)
   267  	}
   268  	if ranges[0].Length != 65536 {
   269  		t.Fatalf("wanted 65536, got %d instead", ranges[0].Length)
   270  	}
   271  }