idtools_unix_test.go 7.0 KB

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