mount_linux_test.go 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919
  1. // +build linux
  2. /*
  3. Copyright 2014 The Kubernetes Authors.
  4. Licensed under the Apache License, Version 2.0 (the "License");
  5. you may not use this file except in compliance with the License.
  6. You may obtain a copy of the License at
  7. http://www.apache.org/licenses/LICENSE-2.0
  8. Unless required by applicable law or agreed to in writing, software
  9. distributed under the License is distributed on an "AS IS" BASIS,
  10. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. See the License for the specific language governing permissions and
  12. limitations under the License.
  13. */
  14. package mount
  15. import (
  16. "fmt"
  17. "io/ioutil"
  18. "net"
  19. "os"
  20. "path/filepath"
  21. "reflect"
  22. "strings"
  23. "testing"
  24. "k8s.io/utils/exec"
  25. )
  26. func TestReadProcMountsFrom(t *testing.T) {
  27. successCase :=
  28. `/dev/0 /path/to/0 type0 flags 0 0
  29. /dev/1 /path/to/1 type1 flags 1 1
  30. /dev/2 /path/to/2 type2 flags,1,2=3 2 2
  31. `
  32. // NOTE: readProcMountsFrom has been updated to using fnv.New32a()
  33. mounts, err := parseProcMounts([]byte(successCase))
  34. if err != nil {
  35. t.Errorf("expected success, got %v", err)
  36. }
  37. if len(mounts) != 3 {
  38. t.Fatalf("expected 3 mounts, got %d", len(mounts))
  39. }
  40. mp := MountPoint{"/dev/0", "/path/to/0", "type0", []string{"flags"}, 0, 0}
  41. if !mountPointsEqual(&mounts[0], &mp) {
  42. t.Errorf("got unexpected MountPoint[0]: %#v", mounts[0])
  43. }
  44. mp = MountPoint{"/dev/1", "/path/to/1", "type1", []string{"flags"}, 1, 1}
  45. if !mountPointsEqual(&mounts[1], &mp) {
  46. t.Errorf("got unexpected MountPoint[1]: %#v", mounts[1])
  47. }
  48. mp = MountPoint{"/dev/2", "/path/to/2", "type2", []string{"flags", "1", "2=3"}, 2, 2}
  49. if !mountPointsEqual(&mounts[2], &mp) {
  50. t.Errorf("got unexpected MountPoint[2]: %#v", mounts[2])
  51. }
  52. errorCases := []string{
  53. "/dev/0 /path/to/mount\n",
  54. "/dev/1 /path/to/mount type flags a 0\n",
  55. "/dev/2 /path/to/mount type flags 0 b\n",
  56. }
  57. for _, ec := range errorCases {
  58. _, err := parseProcMounts([]byte(ec))
  59. if err == nil {
  60. t.Errorf("expected error")
  61. }
  62. }
  63. }
  64. func mountPointsEqual(a, b *MountPoint) bool {
  65. if a.Device != b.Device || a.Path != b.Path || a.Type != b.Type || !reflect.DeepEqual(a.Opts, b.Opts) || a.Pass != b.Pass || a.Freq != b.Freq {
  66. return false
  67. }
  68. return true
  69. }
  70. func TestGetMountRefs(t *testing.T) {
  71. fm := &FakeMounter{
  72. MountPoints: []MountPoint{
  73. {Device: "/dev/sdb", Path: "/var/lib/kubelet/plugins/kubernetes.io/gce-pd/mounts/gce-pd"},
  74. {Device: "/dev/sdb", Path: "/var/lib/kubelet/pods/some-pod/volumes/kubernetes.io~gce-pd/gce-pd-in-pod"},
  75. {Device: "/dev/sdc", Path: "/var/lib/kubelet/plugins/kubernetes.io/gce-pd/mounts/gce-pd2"},
  76. {Device: "/dev/sdc", Path: "/var/lib/kubelet/pods/some-pod/volumes/kubernetes.io~gce-pd/gce-pd2-in-pod1"},
  77. {Device: "/dev/sdc", Path: "/var/lib/kubelet/pods/some-pod/volumes/kubernetes.io~gce-pd/gce-pd2-in-pod2"},
  78. },
  79. }
  80. tests := []struct {
  81. mountPath string
  82. expectedRefs []string
  83. }{
  84. {
  85. "/var/lib/kubelet/pods/some-pod/volumes/kubernetes.io~gce-pd/gce-pd-in-pod",
  86. []string{
  87. "/var/lib/kubelet/plugins/kubernetes.io/gce-pd/mounts/gce-pd",
  88. },
  89. },
  90. {
  91. "/var/lib/kubelet/pods/some-pod/volumes/kubernetes.io~gce-pd/gce-pd2-in-pod1",
  92. []string{
  93. "/var/lib/kubelet/pods/some-pod/volumes/kubernetes.io~gce-pd/gce-pd2-in-pod2",
  94. "/var/lib/kubelet/plugins/kubernetes.io/gce-pd/mounts/gce-pd2",
  95. },
  96. },
  97. {
  98. "/var/fake/directory/that/doesnt/exist",
  99. []string{},
  100. },
  101. }
  102. for i, test := range tests {
  103. if refs, err := fm.GetMountRefs(test.mountPath); err != nil || !setEquivalent(test.expectedRefs, refs) {
  104. t.Errorf("%d. getMountRefs(%q) = %v, %v; expected %v, nil", i, test.mountPath, refs, err, test.expectedRefs)
  105. }
  106. }
  107. }
  108. func setEquivalent(set1, set2 []string) bool {
  109. map1 := make(map[string]bool)
  110. map2 := make(map[string]bool)
  111. for _, s := range set1 {
  112. map1[s] = true
  113. }
  114. for _, s := range set2 {
  115. map2[s] = true
  116. }
  117. for s := range map1 {
  118. if !map2[s] {
  119. return false
  120. }
  121. }
  122. for s := range map2 {
  123. if !map1[s] {
  124. return false
  125. }
  126. }
  127. return true
  128. }
  129. func TestGetDeviceNameFromMount(t *testing.T) {
  130. fm := &FakeMounter{
  131. MountPoints: []MountPoint{
  132. {Device: "/dev/disk/by-path/prefix-lun-1",
  133. Path: "/mnt/111"},
  134. {Device: "/dev/disk/by-path/prefix-lun-1",
  135. Path: "/mnt/222"},
  136. },
  137. }
  138. tests := []struct {
  139. mountPath string
  140. expectedDevice string
  141. expectedRefs int
  142. }{
  143. {
  144. "/mnt/222",
  145. "/dev/disk/by-path/prefix-lun-1",
  146. 2,
  147. },
  148. }
  149. for i, test := range tests {
  150. if device, refs, err := GetDeviceNameFromMount(fm, test.mountPath); err != nil || test.expectedRefs != refs || test.expectedDevice != device {
  151. t.Errorf("%d. GetDeviceNameFromMount(%s) = (%s, %d), %v; expected (%s,%d), nil", i, test.mountPath, device, refs, err, test.expectedDevice, test.expectedRefs)
  152. }
  153. }
  154. }
  155. func TestGetMountRefsByDev(t *testing.T) {
  156. fm := &FakeMounter{
  157. MountPoints: []MountPoint{
  158. {Device: "/dev/sdb", Path: "/var/lib/kubelet/plugins/kubernetes.io/gce-pd/mounts/gce-pd"},
  159. {Device: "/dev/sdb", Path: "/var/lib/kubelet/pods/some-pod/volumes/kubernetes.io~gce-pd/gce-pd-in-pod"},
  160. {Device: "/dev/sdc", Path: "/var/lib/kubelet/plugins/kubernetes.io/gce-pd/mounts/gce-pd2"},
  161. {Device: "/dev/sdc", Path: "/var/lib/kubelet/pods/some-pod/volumes/kubernetes.io~gce-pd/gce-pd2-in-pod1"},
  162. {Device: "/dev/sdc", Path: "/var/lib/kubelet/pods/some-pod/volumes/kubernetes.io~gce-pd/gce-pd2-in-pod2"},
  163. },
  164. }
  165. tests := []struct {
  166. mountPath string
  167. expectedRefs []string
  168. }{
  169. {
  170. "/var/lib/kubelet/plugins/kubernetes.io/gce-pd/mounts/gce-pd",
  171. []string{
  172. "/var/lib/kubelet/pods/some-pod/volumes/kubernetes.io~gce-pd/gce-pd-in-pod",
  173. },
  174. },
  175. {
  176. "/var/lib/kubelet/plugins/kubernetes.io/gce-pd/mounts/gce-pd2",
  177. []string{
  178. "/var/lib/kubelet/pods/some-pod/volumes/kubernetes.io~gce-pd/gce-pd2-in-pod1",
  179. "/var/lib/kubelet/pods/some-pod/volumes/kubernetes.io~gce-pd/gce-pd2-in-pod2",
  180. },
  181. },
  182. }
  183. for i, test := range tests {
  184. if refs, err := getMountRefsByDev(fm, test.mountPath); err != nil || !setEquivalent(test.expectedRefs, refs) {
  185. t.Errorf("%d. getMountRefsByDev(%q) = %v, %v; expected %v, nil", i, test.mountPath, refs, err, test.expectedRefs)
  186. }
  187. }
  188. }
  189. func writeFile(content string) (string, string, error) {
  190. tempDir, err := ioutil.TempDir("", "mounter_shared_test")
  191. if err != nil {
  192. return "", "", err
  193. }
  194. filename := filepath.Join(tempDir, "mountinfo")
  195. err = ioutil.WriteFile(filename, []byte(content), 0600)
  196. if err != nil {
  197. os.RemoveAll(tempDir)
  198. return "", "", err
  199. }
  200. return tempDir, filename, nil
  201. }
  202. func TestIsSharedSuccess(t *testing.T) {
  203. successMountInfo :=
  204. `62 0 253:0 / / rw,relatime shared:1 - ext4 /dev/mapper/ssd-root rw,seclabel,data=ordered
  205. 76 62 8:1 / /boot rw,relatime shared:29 - ext4 /dev/sda1 rw,seclabel,data=ordered
  206. 78 62 0:41 / /tmp rw,nosuid,nodev shared:30 - tmpfs tmpfs rw,seclabel
  207. 80 62 0:42 / /var/lib/nfs/rpc_pipefs rw,relatime shared:31 - rpc_pipefs sunrpc rw
  208. 82 62 0:43 / /var/lib/foo rw,relatime shared:32 - tmpfs tmpfs rw
  209. 83 63 0:44 / /var/lib/bar rw,relatime - tmpfs tmpfs rw
  210. 227 62 253:0 /var/lib/docker/devicemapper /var/lib/docker/devicemapper rw,relatime - ext4 /dev/mapper/ssd-root rw,seclabel,data=ordered
  211. 224 62 253:0 /var/lib/docker/devicemapper/test/shared /var/lib/docker/devicemapper/test/shared rw,relatime master:1 shared:44 - ext4 /dev/mapper/ssd-root rw,seclabel,data=ordered
  212. `
  213. tempDir, filename, err := writeFile(successMountInfo)
  214. if err != nil {
  215. t.Fatalf("cannot create temporary file: %v", err)
  216. }
  217. defer os.RemoveAll(tempDir)
  218. tests := []struct {
  219. name string
  220. path string
  221. expectedResult bool
  222. }{
  223. {
  224. // /var/lib/kubelet is a directory on mount '/' that is shared
  225. // This is the most common case.
  226. "shared",
  227. "/var/lib/kubelet",
  228. true,
  229. },
  230. {
  231. // 8a2a... is a directory on mount /var/lib/docker/devicemapper
  232. // that is private.
  233. "private",
  234. "/var/lib/docker/devicemapper/mnt/8a2a5c19eefb06d6f851dfcb240f8c113427f5b49b19658b5c60168e88267693/",
  235. false,
  236. },
  237. {
  238. // 'directory' is a directory on mount
  239. // /var/lib/docker/devicemapper/test/shared that is shared, but one
  240. // of its parent is private.
  241. "nested-shared",
  242. "/var/lib/docker/devicemapper/test/shared/my/test/directory",
  243. true,
  244. },
  245. {
  246. // /var/lib/foo is a mount point and it's shared
  247. "shared-mount",
  248. "/var/lib/foo",
  249. true,
  250. },
  251. {
  252. // /var/lib/bar is a mount point and it's private
  253. "private-mount",
  254. "/var/lib/bar",
  255. false,
  256. },
  257. }
  258. for _, test := range tests {
  259. ret, err := isShared(test.path, filename)
  260. if err != nil {
  261. t.Errorf("test %s got unexpected error: %v", test.name, err)
  262. }
  263. if ret != test.expectedResult {
  264. t.Errorf("test %s expected %v, got %v", test.name, test.expectedResult, ret)
  265. }
  266. }
  267. }
  268. func TestIsSharedFailure(t *testing.T) {
  269. errorTests := []struct {
  270. name string
  271. content string
  272. }{
  273. {
  274. // the first line is too short
  275. name: "too-short-line",
  276. content: `62 0 253:0 / / rw,relatime
  277. 76 62 8:1 / /boot rw,relatime shared:29 - ext4 /dev/sda1 rw,seclabel,data=ordered
  278. 78 62 0:41 / /tmp rw,nosuid,nodev shared:30 - tmpfs tmpfs rw,seclabel
  279. 80 62 0:42 / /var/lib/nfs/rpc_pipefs rw,relatime shared:31 - rpc_pipefs sunrpc rw
  280. 227 62 253:0 /var/lib/docker/devicemapper /var/lib/docker/devicemapper rw,relatime - ext4 /dev/mapper/ssd-root rw,seclabel,data=ordered
  281. 224 62 253:0 /var/lib/docker/devicemapper/test/shared /var/lib/docker/devicemapper/test/shared rw,relatime master:1 shared:44 - ext4 /dev/mapper/ssd-root rw,seclabel,data=ordered
  282. `,
  283. },
  284. {
  285. // there is no root mount
  286. name: "no-root-mount",
  287. content: `76 62 8:1 / /boot rw,relatime shared:29 - ext4 /dev/sda1 rw,seclabel,data=ordered
  288. 78 62 0:41 / /tmp rw,nosuid,nodev shared:30 - tmpfs tmpfs rw,seclabel
  289. 80 62 0:42 / /var/lib/nfs/rpc_pipefs rw,relatime shared:31 - rpc_pipefs sunrpc rw
  290. 227 62 253:0 /var/lib/docker/devicemapper /var/lib/docker/devicemapper rw,relatime - ext4 /dev/mapper/ssd-root rw,seclabel,data=ordered
  291. 224 62 253:0 /var/lib/docker/devicemapper/test/shared /var/lib/docker/devicemapper/test/shared rw,relatime master:1 shared:44 - ext4 /dev/mapper/ssd-root rw,seclabel,data=ordered
  292. `,
  293. },
  294. }
  295. for _, test := range errorTests {
  296. tempDir, filename, err := writeFile(test.content)
  297. if err != nil {
  298. t.Fatalf("cannot create temporary file: %v", err)
  299. }
  300. defer os.RemoveAll(tempDir)
  301. _, err = isShared("/", filename)
  302. if err == nil {
  303. t.Errorf("test %q: expected error, got none", test.name)
  304. }
  305. }
  306. }
  307. func TestPathWithinBase(t *testing.T) {
  308. tests := []struct {
  309. name string
  310. fullPath string
  311. basePath string
  312. expected bool
  313. }{
  314. {
  315. name: "good subpath",
  316. fullPath: "/a/b/c",
  317. basePath: "/a",
  318. expected: true,
  319. },
  320. {
  321. name: "good subpath 2",
  322. fullPath: "/a/b/c",
  323. basePath: "/a/b",
  324. expected: true,
  325. },
  326. {
  327. name: "good subpath end slash",
  328. fullPath: "/a/b/c/",
  329. basePath: "/a/b",
  330. expected: true,
  331. },
  332. {
  333. name: "good subpath backticks",
  334. fullPath: "/a/b/../c",
  335. basePath: "/a",
  336. expected: true,
  337. },
  338. {
  339. name: "good subpath equal",
  340. fullPath: "/a/b/c",
  341. basePath: "/a/b/c",
  342. expected: true,
  343. },
  344. {
  345. name: "good subpath equal 2",
  346. fullPath: "/a/b/c/",
  347. basePath: "/a/b/c",
  348. expected: true,
  349. },
  350. {
  351. name: "good subpath root",
  352. fullPath: "/a",
  353. basePath: "/",
  354. expected: true,
  355. },
  356. {
  357. name: "bad subpath parent",
  358. fullPath: "/a/b/c",
  359. basePath: "/a/b/c/d",
  360. expected: false,
  361. },
  362. {
  363. name: "bad subpath outside",
  364. fullPath: "/b/c",
  365. basePath: "/a/b/c",
  366. expected: false,
  367. },
  368. {
  369. name: "bad subpath prefix",
  370. fullPath: "/a/b/cd",
  371. basePath: "/a/b/c",
  372. expected: false,
  373. },
  374. {
  375. name: "bad subpath backticks",
  376. fullPath: "/a/../b",
  377. basePath: "/a",
  378. expected: false,
  379. },
  380. {
  381. name: "configmap subpath",
  382. fullPath: "/var/lib/kubelet/pods/uuid/volumes/kubernetes.io~configmap/config/..timestamp/file.txt",
  383. basePath: "/var/lib/kubelet/pods/uuid/volumes/kubernetes.io~configmap/config",
  384. expected: true,
  385. },
  386. }
  387. for _, test := range tests {
  388. if PathWithinBase(test.fullPath, test.basePath) != test.expected {
  389. t.Errorf("test %q failed: expected %v", test.name, test.expected)
  390. }
  391. }
  392. }
  393. func TestParseMountInfo(t *testing.T) {
  394. info :=
  395. `62 0 253:0 / / rw,relatime shared:1 - ext4 /dev/mapper/ssd-root rw,seclabel,data=ordered
  396. 78 62 0:41 / /tmp rw,nosuid,nodev shared:30 - tmpfs tmpfs rw,seclabel
  397. 80 62 0:42 / /var/lib/nfs/rpc_pipefs rw,relatime shared:31 - rpc_pipefs sunrpc rw
  398. 82 62 0:43 / /var/lib/foo rw,relatime shared:32 - tmpfs tmpfs rw
  399. 83 63 0:44 / /var/lib/bar rw,relatime - tmpfs tmpfs rw
  400. 227 62 253:0 /var/lib/docker/devicemapper /var/lib/docker/devicemapper rw,relatime - ext4 /dev/mapper/ssd-root rw,seclabel,data=ordered
  401. 224 62 253:0 /var/lib/docker/devicemapper/test/shared /var/lib/docker/devicemapper/test/shared rw,relatime master:1 shared:44 - ext4 /dev/mapper/ssd-root rw,seclabel,data=ordered
  402. 76 17 8:1 / /mnt/stateful_partition rw,nosuid,nodev,noexec,relatime - ext4 /dev/sda1 rw,commit=30,data=ordered
  403. 80 17 8:1 /var /var rw,nosuid,nodev,noexec,relatime shared:30 - ext4 /dev/sda1 rw,commit=30,data=ordered
  404. 189 80 8:1 /var/lib/kubelet /var/lib/kubelet rw,relatime shared:30 - ext4 /dev/sda1 rw,commit=30,data=ordered
  405. 818 77 8:40 / /var/lib/kubelet/pods/c25464af-e52e-11e7-ab4d-42010a800002/volumes/kubernetes.io~gce-pd/vol1 rw,relatime shared:290 - ext4 /dev/sdc rw,data=ordered
  406. 819 78 8:48 / /var/lib/kubelet/pods/c25464af-e52e-11e7-ab4d-42010a800002/volumes/kubernetes.io~gce-pd/vol1 rw,relatime shared:290 - ext4 /dev/sdd rw,data=ordered
  407. 900 100 8:48 /dir1 /var/lib/kubelet/pods/c25464af-e52e-11e7-ab4d-42010a800002/volume-subpaths/vol1/subpath1/0 rw,relatime shared:290 - ext4 /dev/sdd rw,data=ordered
  408. 901 101 8:1 /dir1 /var/lib/kubelet/pods/c25464af-e52e-11e7-ab4d-42010a800002/volume-subpaths/vol1/subpath1/1 rw,relatime shared:290 - ext4 /dev/sdd rw,data=ordered
  409. 902 102 8:1 /var/lib/kubelet/pods/d4076f24-e53a-11e7-ba15-42010a800002/volumes/kubernetes.io~empty-dir/vol1/dir1 /var/lib/kubelet/pods/d4076f24-e53a-11e7-ba15-42010a800002/volume-subpaths/vol1/subpath1/0 rw,relatime shared:30 - ext4 /dev/sda1 rw,commit=30,data=ordered
  410. 903 103 8:1 /var/lib/kubelet/pods/d4076f24-e53a-11e7-ba15-42010a800002/volumes/kubernetes.io~empty-dir/vol2/dir1 /var/lib/kubelet/pods/d4076f24-e53a-11e7-ba15-42010a800002/volume-subpaths/vol1/subpath1/1 rw,relatime shared:30 - ext4 /dev/sda1 rw,commit=30,data=ordered
  411. 178 25 253:0 /etc/bar /var/lib/kubelet/pods/12345/volume-subpaths/vol1/subpath1/0 rw,relatime shared:1 - ext4 /dev/sdb2 rw,errors=remount-ro,data=ordered
  412. 698 186 0:41 /tmp1/dir1 /var/lib/kubelet/pods/41135147-e697-11e7-9342-42010a800002/volume-subpaths/vol1/subpath1/0 rw shared:26 - tmpfs tmpfs rw
  413. 918 77 8:50 / /var/lib/kubelet/pods/2345/volumes/kubernetes.io~gce-pd/vol1 rw,relatime shared:290 - ext4 /dev/sdc rw,data=ordered
  414. 919 78 8:58 / /var/lib/kubelet/pods/2345/volumes/kubernetes.io~gce-pd/vol1 rw,relatime shared:290 - ext4 /dev/sdd rw,data=ordered
  415. 920 100 8:50 /dir1 /var/lib/kubelet/pods/2345/volume-subpaths/vol1/subpath1/0 rw,relatime shared:290 - ext4 /dev/sdc rw,data=ordered
  416. 150 23 1:58 / /media/nfs_vol rw,relatime shared:89 - nfs4 172.18.4.223:/srv/nfs rw,vers=4.0,rsize=524288,wsize=524288,namlen=255,hard,proto=tcp,port=0,timeo=600,retrans=2,sec=sys,clientaddr=172.18.4.223,local_lock=none,addr=172.18.4.223
  417. 151 24 1:58 / /media/nfs_bindmount rw,relatime shared:89 - nfs4 172.18.4.223:/srv/nfs/foo rw,vers=4.0,rsize=524288,wsize=524288,namlen=255,hard,proto=tcp,port=0,timeo=600,retrans=2,sec=sys,clientaddr=172.18.4.223,local_lock=none,addr=172.18.4.223
  418. 134 23 0:58 / /var/lib/kubelet/pods/43219158-e5e1-11e7-a392-0e858b8eaf40/volumes/kubernetes.io~nfs/nfs1 rw,relatime shared:89 - nfs4 172.18.4.223:/srv/nfs rw,vers=4.0,rsize=524288,wsize=524288,namlen=255,hard,proto=tcp,port=0,timeo=600,retrans=2,sec=sys,clientaddr=172.18.4.223,local_lock=none,addr=172.18.4.223
  419. 187 23 0:58 / /var/lib/kubelet/pods/1fc5ea21-eff4-11e7-ac80-0e858b8eaf40/volumes/kubernetes.io~nfs/nfs2 rw,relatime shared:96 - nfs4 172.18.4.223:/srv/nfs2 rw,vers=4.0,rsize=524288,wsize=524288,namlen=255,hard,proto=tcp,port=0,timeo=600,retrans=2,sec=sys,clientaddr=172.18.4.223,local_lock=none,addr=172.18.4.223
  420. 188 24 0:58 / /var/lib/kubelet/pods/43219158-e5e1-11e7-a392-0e858b8eaf40/volume-subpaths/nfs1/subpath1/0 rw,relatime shared:89 - nfs4 172.18.4.223:/srv/nfs/foo rw,vers=4.0,rsize=524288,wsize=524288,namlen=255,hard,proto=tcp,port=0,timeo=600,retrans=2,sec=sys,clientaddr=172.18.4.223,local_lock=none,addr=172.18.4.223
  421. 347 60 0:71 / /var/lib/kubelet/pods/13195d46-f9fa-11e7-bbf1-5254007a695a/volumes/kubernetes.io~nfs/vol2 rw,relatime shared:170 - nfs 172.17.0.3:/exports/2 rw,vers=3,rsize=1048576,wsize=1048576,namlen=255,hard,proto=tcp,timeo=600,retrans=2,sec=sys,mountaddr=172.17.0.3,mountvers=3,mountport=20048,mountproto=udp,local_lock=none,addr=172.17.0.3
  422. 222 24 253:0 /tmp/src /mnt/dst rw,relatime shared:1 - ext4 /dev/mapper/vagrant--vg-root rw,errors=remount-ro,data=ordered
  423. 28 18 0:24 / /sys/fs/cgroup ro,nosuid,nodev,noexec shared:9 - tmpfs tmpfs ro,mode=755
  424. 29 28 0:25 / /sys/fs/cgroup/systemd rw,nosuid,nodev,noexec,relatime shared:10 - cgroup cgroup rw,xattr,release_agent=/lib/systemd/systemd-cgroups-agent,name=systemd
  425. 31 28 0:27 / /sys/fs/cgroup/cpuset rw,nosuid,nodev,noexec,relatime shared:13 - cgroup cgroup rw,cpuset
  426. 32 28 0:28 / /sys/fs/cgroup/cpu,cpuacct rw,nosuid,nodev,noexec,relatime shared:14 - cgroup cgroup rw,cpu,cpuacct
  427. 33 28 0:29 / /sys/fs/cgroup/freezer rw,nosuid,nodev,noexec,relatime shared:15 - cgroup cgroup rw,freezer
  428. 34 28 0:30 / /sys/fs/cgroup/net_cls,net_prio rw,nosuid,nodev,noexec,relatime shared:16 - cgroup cgroup rw,net_cls,net_prio
  429. 35 28 0:31 / /sys/fs/cgroup/pids rw,nosuid,nodev,noexec,relatime shared:17 - cgroup cgroup rw,pids
  430. 36 28 0:32 / /sys/fs/cgroup/devices rw,nosuid,nodev,noexec,relatime shared:18 - cgroup cgroup rw,devices
  431. 37 28 0:33 / /sys/fs/cgroup/hugetlb rw,nosuid,nodev,noexec,relatime shared:19 - cgroup cgroup rw,hugetlb
  432. 38 28 0:34 / /sys/fs/cgroup/blkio rw,nosuid,nodev,noexec,relatime shared:20 - cgroup cgroup rw,blkio
  433. 39 28 0:35 / /sys/fs/cgroup/memory rw,nosuid,nodev,noexec,relatime shared:21 - cgroup cgroup rw,memory
  434. 40 28 0:36 / /sys/fs/cgroup/perf_event rw,nosuid,nodev,noexec,relatime shared:22 - cgroup cgroup rw,perf_event
  435. `
  436. tempDir, filename, err := writeFile(info)
  437. if err != nil {
  438. t.Fatalf("cannot create temporary file: %v", err)
  439. }
  440. defer os.RemoveAll(tempDir)
  441. tests := []struct {
  442. name string
  443. id int
  444. expectedInfo mountInfo
  445. }{
  446. {
  447. "simple bind mount",
  448. 189,
  449. mountInfo{
  450. id: 189,
  451. parentID: 80,
  452. majorMinor: "8:1",
  453. root: "/var/lib/kubelet",
  454. source: "/dev/sda1",
  455. mountPoint: "/var/lib/kubelet",
  456. optionalFields: []string{"shared:30"},
  457. fsType: "ext4",
  458. mountOptions: []string{"rw", "relatime"},
  459. superOptions: []string{"rw", "commit=30", "data=ordered"},
  460. },
  461. },
  462. {
  463. "bind mount a directory",
  464. 222,
  465. mountInfo{
  466. id: 222,
  467. parentID: 24,
  468. majorMinor: "253:0",
  469. root: "/tmp/src",
  470. source: "/dev/mapper/vagrant--vg-root",
  471. mountPoint: "/mnt/dst",
  472. optionalFields: []string{"shared:1"},
  473. fsType: "ext4",
  474. mountOptions: []string{"rw", "relatime"},
  475. superOptions: []string{"rw", "errors=remount-ro", "data=ordered"},
  476. },
  477. },
  478. {
  479. "more than one optional fields",
  480. 224,
  481. mountInfo{
  482. id: 224,
  483. parentID: 62,
  484. majorMinor: "253:0",
  485. root: "/var/lib/docker/devicemapper/test/shared",
  486. source: "/dev/mapper/ssd-root",
  487. mountPoint: "/var/lib/docker/devicemapper/test/shared",
  488. optionalFields: []string{"master:1", "shared:44"},
  489. fsType: "ext4",
  490. mountOptions: []string{"rw", "relatime"},
  491. superOptions: []string{"rw", "seclabel", "data=ordered"},
  492. },
  493. },
  494. {
  495. "cgroup-mountpoint",
  496. 28,
  497. mountInfo{
  498. id: 28,
  499. parentID: 18,
  500. majorMinor: "0:24",
  501. root: "/",
  502. source: "tmpfs",
  503. mountPoint: "/sys/fs/cgroup",
  504. optionalFields: []string{"shared:9"},
  505. fsType: "tmpfs",
  506. mountOptions: []string{"ro", "nosuid", "nodev", "noexec"},
  507. superOptions: []string{"ro", "mode=755"},
  508. },
  509. },
  510. {
  511. "cgroup-subsystem-systemd-mountpoint",
  512. 29,
  513. mountInfo{
  514. id: 29,
  515. parentID: 28,
  516. majorMinor: "0:25",
  517. root: "/",
  518. source: "cgroup",
  519. mountPoint: "/sys/fs/cgroup/systemd",
  520. optionalFields: []string{"shared:10"},
  521. fsType: "cgroup",
  522. mountOptions: []string{"rw", "nosuid", "nodev", "noexec", "relatime"},
  523. superOptions: []string{"rw", "xattr", "release_agent=/lib/systemd/systemd-cgroups-agent", "name=systemd"},
  524. },
  525. },
  526. {
  527. "cgroup-subsystem-cpuset-mountpoint",
  528. 31,
  529. mountInfo{
  530. id: 31,
  531. parentID: 28,
  532. majorMinor: "0:27",
  533. root: "/",
  534. source: "cgroup",
  535. mountPoint: "/sys/fs/cgroup/cpuset",
  536. optionalFields: []string{"shared:13"},
  537. fsType: "cgroup",
  538. mountOptions: []string{"rw", "nosuid", "nodev", "noexec", "relatime"},
  539. superOptions: []string{"rw", "cpuset"},
  540. },
  541. },
  542. }
  543. infos, err := parseMountInfo(filename)
  544. if err != nil {
  545. t.Fatalf("Cannot parse %s: %s", filename, err)
  546. }
  547. for _, test := range tests {
  548. found := false
  549. for _, info := range infos {
  550. if info.id == test.id {
  551. found = true
  552. if !reflect.DeepEqual(info, test.expectedInfo) {
  553. t.Errorf("Test case %q:\n expected: %+v\n got: %+v", test.name, test.expectedInfo, info)
  554. }
  555. break
  556. }
  557. }
  558. if !found {
  559. t.Errorf("Test case %q: mountPoint %d not found", test.name, test.id)
  560. }
  561. }
  562. }
  563. func TestGetSELinuxSupport(t *testing.T) {
  564. info :=
  565. `62 0 253:0 / / rw,relatime shared:1 - ext4 /dev/mapper/ssd-root rw,seclabel,data=ordered
  566. 78 62 0:41 / /tmp rw,nosuid,nodev shared:30 - tmpfs tmpfs rw,seclabel
  567. 83 63 0:44 / /var/lib/bar rw,relatime - tmpfs tmpfs rw
  568. 227 62 253:0 /var/lib/docker/devicemapper /var/lib/docker/devicemapper rw,relatime - ext4 /dev/mapper/ssd-root rw,seclabel,data=ordered
  569. 150 23 1:58 / /media/nfs_vol rw,relatime shared:89 - nfs4 172.18.4.223:/srv/nfs rw,vers=4.0,rsize=524288,wsize=524288,namlen=255,hard,proto=tcp,port=0,timeo=600,retrans=2,sec=sys,clientaddr=172.18.4.223,local_lock=none,addr=172.18.4.223
  570. `
  571. tempDir, filename, err := writeFile(info)
  572. if err != nil {
  573. t.Fatalf("cannot create temporary file: %v", err)
  574. }
  575. defer os.RemoveAll(tempDir)
  576. tests := []struct {
  577. name string
  578. mountPoint string
  579. expectedResult bool
  580. }{
  581. {
  582. "ext4 on /",
  583. "/",
  584. true,
  585. },
  586. {
  587. "tmpfs on /var/lib/bar",
  588. "/var/lib/bar",
  589. false,
  590. },
  591. {
  592. "nfsv4",
  593. "/media/nfs_vol",
  594. false,
  595. },
  596. }
  597. for _, test := range tests {
  598. out, err := GetSELinux(test.mountPoint, filename)
  599. if err != nil {
  600. t.Errorf("Test %s failed with error: %s", test.name, err)
  601. }
  602. if test.expectedResult != out {
  603. t.Errorf("Test %s failed: expected %v, got %v", test.name, test.expectedResult, out)
  604. }
  605. }
  606. }
  607. func createSocketFile(socketDir string) (string, error) {
  608. testSocketFile := filepath.Join(socketDir, "mt.sock")
  609. // Switch to volume path and create the socket file
  610. // socket file can not have length of more than 108 character
  611. // and hence we must use relative path
  612. oldDir, _ := os.Getwd()
  613. err := os.Chdir(socketDir)
  614. if err != nil {
  615. return "", err
  616. }
  617. defer func() {
  618. os.Chdir(oldDir)
  619. }()
  620. _, socketCreateError := net.Listen("unix", "mt.sock")
  621. return testSocketFile, socketCreateError
  622. }
  623. func TestGetFileType(t *testing.T) {
  624. mounter := Mounter{"fake/path", false}
  625. testCase := []struct {
  626. name string
  627. expectedType FileType
  628. setUp func() (string, string, error)
  629. }{
  630. {
  631. "Directory Test",
  632. FileTypeDirectory,
  633. func() (string, string, error) {
  634. tempDir, err := ioutil.TempDir("", "test-get-filetype-")
  635. return tempDir, tempDir, err
  636. },
  637. },
  638. {
  639. "File Test",
  640. FileTypeFile,
  641. func() (string, string, error) {
  642. tempFile, err := ioutil.TempFile("", "test-get-filetype")
  643. if err != nil {
  644. return "", "", err
  645. }
  646. tempFile.Close()
  647. return tempFile.Name(), tempFile.Name(), nil
  648. },
  649. },
  650. {
  651. "Socket Test",
  652. FileTypeSocket,
  653. func() (string, string, error) {
  654. tempDir, err := ioutil.TempDir("", "test-get-filetype-")
  655. if err != nil {
  656. return "", "", err
  657. }
  658. tempSocketFile, err := createSocketFile(tempDir)
  659. return tempSocketFile, tempDir, err
  660. },
  661. },
  662. {
  663. "Block Device Test",
  664. FileTypeBlockDev,
  665. func() (string, string, error) {
  666. tempDir, err := ioutil.TempDir("", "test-get-filetype-")
  667. if err != nil {
  668. return "", "", err
  669. }
  670. tempBlockFile := filepath.Join(tempDir, "test_blk_dev")
  671. outputBytes, err := exec.New().Command("mknod", tempBlockFile, "b", "89", "1").CombinedOutput()
  672. if err != nil {
  673. err = fmt.Errorf("%v: %s ", err, outputBytes)
  674. }
  675. return tempBlockFile, tempDir, err
  676. },
  677. },
  678. {
  679. "Character Device Test",
  680. FileTypeCharDev,
  681. func() (string, string, error) {
  682. tempDir, err := ioutil.TempDir("", "test-get-filetype-")
  683. if err != nil {
  684. return "", "", err
  685. }
  686. tempCharFile := filepath.Join(tempDir, "test_char_dev")
  687. outputBytes, err := exec.New().Command("mknod", tempCharFile, "c", "89", "1").CombinedOutput()
  688. if err != nil {
  689. err = fmt.Errorf("%v: %s ", err, outputBytes)
  690. }
  691. return tempCharFile, tempDir, err
  692. },
  693. },
  694. }
  695. for idx, tc := range testCase {
  696. path, cleanUpPath, err := tc.setUp()
  697. if err != nil {
  698. // Locally passed, but upstream CI is not friendly to create such device files
  699. // Leave "Operation not permitted" out, which can be covered in an e2e test
  700. if isOperationNotPermittedError(err) {
  701. continue
  702. }
  703. t.Fatalf("[%d-%s] unexpected error : %v", idx, tc.name, err)
  704. }
  705. if len(cleanUpPath) > 0 {
  706. defer os.RemoveAll(cleanUpPath)
  707. }
  708. fileType, err := mounter.GetFileType(path)
  709. if err != nil {
  710. t.Fatalf("[%d-%s] unexpected error : %v", idx, tc.name, err)
  711. }
  712. if fileType != tc.expectedType {
  713. t.Fatalf("[%d-%s] expected %s, but got %s", idx, tc.name, tc.expectedType, fileType)
  714. }
  715. }
  716. }
  717. func isOperationNotPermittedError(err error) bool {
  718. if strings.Contains(err.Error(), "Operation not permitted") {
  719. return true
  720. }
  721. return false
  722. }
  723. func TestSearchMountPoints(t *testing.T) {
  724. base := `
  725. 19 25 0:18 / /sys rw,nosuid,nodev,noexec,relatime shared:7 - sysfs sysfs rw
  726. 20 25 0:4 / /proc rw,nosuid,nodev,noexec,relatime shared:12 - proc proc rw
  727. 21 25 0:6 / /dev rw,nosuid,relatime shared:2 - devtmpfs udev rw,size=4058156k,nr_inodes=1014539,mode=755
  728. 22 21 0:14 / /dev/pts rw,nosuid,noexec,relatime shared:3 - devpts devpts rw,gid=5,mode=620,ptmxmode=000
  729. 23 25 0:19 / /run rw,nosuid,noexec,relatime shared:5 - tmpfs tmpfs rw,size=815692k,mode=755
  730. 25 0 252:0 / / rw,relatime shared:1 - ext4 /dev/mapper/ubuntu--vg-root rw,errors=remount-ro,data=ordered
  731. 26 19 0:12 / /sys/kernel/security rw,nosuid,nodev,noexec,relatime shared:8 - securityfs securityfs rw
  732. 27 21 0:21 / /dev/shm rw,nosuid,nodev shared:4 - tmpfs tmpfs rw
  733. 28 23 0:22 / /run/lock rw,nosuid,nodev,noexec,relatime shared:6 - tmpfs tmpfs rw,size=5120k
  734. 29 19 0:23 / /sys/fs/cgroup ro,nosuid,nodev,noexec shared:9 - tmpfs tmpfs ro,mode=755
  735. 30 29 0:24 / /sys/fs/cgroup/systemd rw,nosuid,nodev,noexec,relatime shared:10 - cgroup cgroup rw,xattr,release_agent=/lib/systemd/systemd-cgroups-agent,name=systemd
  736. 31 19 0:25 / /sys/fs/pstore rw,nosuid,nodev,noexec,relatime shared:11 - pstore pstore rw
  737. 32 29 0:26 / /sys/fs/cgroup/devices rw,nosuid,nodev,noexec,relatime shared:13 - cgroup cgroup rw,devices
  738. 33 29 0:27 / /sys/fs/cgroup/freezer rw,nosuid,nodev,noexec,relatime shared:14 - cgroup cgroup rw,freezer
  739. 34 29 0:28 / /sys/fs/cgroup/pids rw,nosuid,nodev,noexec,relatime shared:15 - cgroup cgroup rw,pids
  740. 35 29 0:29 / /sys/fs/cgroup/blkio rw,nosuid,nodev,noexec,relatime shared:16 - cgroup cgroup rw,blkio
  741. 36 29 0:30 / /sys/fs/cgroup/memory rw,nosuid,nodev,noexec,relatime shared:17 - cgroup cgroup rw,memory
  742. 37 29 0:31 / /sys/fs/cgroup/perf_event rw,nosuid,nodev,noexec,relatime shared:18 - cgroup cgroup rw,perf_event
  743. 38 29 0:32 / /sys/fs/cgroup/hugetlb rw,nosuid,nodev,noexec,relatime shared:19 - cgroup cgroup rw,hugetlb
  744. 39 29 0:33 / /sys/fs/cgroup/cpu,cpuacct rw,nosuid,nodev,noexec,relatime shared:20 - cgroup cgroup rw,cpu,cpuacct
  745. 40 29 0:34 / /sys/fs/cgroup/cpuset rw,nosuid,nodev,noexec,relatime shared:21 - cgroup cgroup rw,cpuset
  746. 41 29 0:35 / /sys/fs/cgroup/net_cls,net_prio rw,nosuid,nodev,noexec,relatime shared:22 - cgroup cgroup rw,net_cls,net_prio
  747. 58 25 7:1 / /mnt/disks/blkvol1 rw,relatime shared:38 - ext4 /dev/loop1 rw,data=ordere
  748. `
  749. testcases := []struct {
  750. name string
  751. source string
  752. mountInfos string
  753. expectedRefs []string
  754. expectedErr error
  755. }{
  756. {
  757. "dir",
  758. "/mnt/disks/vol1",
  759. base,
  760. nil,
  761. nil,
  762. },
  763. {
  764. "dir-used",
  765. "/mnt/disks/vol1",
  766. base + `
  767. 56 25 252:0 /mnt/disks/vol1 /var/lib/kubelet/pods/1890aef5-5a60-11e8-962f-000c29bb0377/volumes/kubernetes.io~local-volume/local-pv-test rw,relatime shared:1 - ext4 /dev/mapper/ubuntu--vg-root rw,errors=remount-ro,data=ordered
  768. 57 25 0:45 / /mnt/disks/vol rw,relatime shared:36 - tmpfs tmpfs rw
  769. `,
  770. []string{"/var/lib/kubelet/pods/1890aef5-5a60-11e8-962f-000c29bb0377/volumes/kubernetes.io~local-volume/local-pv-test"},
  771. nil,
  772. },
  773. {
  774. "tmpfs-vol",
  775. "/mnt/disks/vol1",
  776. base + `120 25 0:76 / /mnt/disks/vol1 rw,relatime shared:41 - tmpfs vol1 rw,size=10000k
  777. `,
  778. nil,
  779. nil,
  780. },
  781. {
  782. "tmpfs-vol-used-by-two-pods",
  783. "/mnt/disks/vol1",
  784. base + `120 25 0:76 / /mnt/disks/vol1 rw,relatime shared:41 - tmpfs vol1 rw,size=10000k
  785. 196 25 0:76 / /var/lib/kubelet/pods/ade3ac21-5a5b-11e8-8559-000c29bb0377/volumes/kubernetes.io~local-volume/local-pv-8f263585 rw,relatime shared:41 - tmpfs vol1 rw,size=10000k
  786. 228 25 0:76 / /var/lib/kubelet/pods/ac60532d-5a5b-11e8-8559-000c29bb0377/volumes/kubernetes.io~local-volume/local-pv-8f263585 rw,relatime shared:41 - tmpfs vol1 rw,size=10000k
  787. `,
  788. []string{
  789. "/var/lib/kubelet/pods/ade3ac21-5a5b-11e8-8559-000c29bb0377/volumes/kubernetes.io~local-volume/local-pv-8f263585",
  790. "/var/lib/kubelet/pods/ac60532d-5a5b-11e8-8559-000c29bb0377/volumes/kubernetes.io~local-volume/local-pv-8f263585",
  791. },
  792. nil,
  793. },
  794. {
  795. "tmpfs-subdir-used-indirectly-via-bindmount-dir-by-one-pod",
  796. "/mnt/vol1/foo",
  797. base + `177 25 0:46 / /mnt/data rw,relatime shared:37 - tmpfs data rw
  798. 190 25 0:46 /vol1 /mnt/vol1 rw,relatime shared:37 - tmpfs data rw
  799. 191 25 0:46 /vol2 /mnt/vol2 rw,relatime shared:37 - tmpfs data rw
  800. 62 25 0:46 /vol1/foo /var/lib/kubelet/pods/e25f2f01-5b06-11e8-8694-000c29bb0377/volumes/kubernetes.io~local-volume/local-pv-test rw,relatime shared:37 - tmpfs data rw
  801. `,
  802. []string{"/var/lib/kubelet/pods/e25f2f01-5b06-11e8-8694-000c29bb0377/volumes/kubernetes.io~local-volume/local-pv-test"},
  803. nil,
  804. },
  805. {
  806. "dir-bindmounted",
  807. "/mnt/disks/vol2",
  808. base + `342 25 252:0 /mnt/disks/vol2 /mnt/disks/vol2 rw,relatime shared:1 - ext4 /dev/mapper/ubuntu--vg-root rw,errors=remount-ro,data=ordered
  809. `,
  810. nil,
  811. nil,
  812. },
  813. {
  814. "dir-bindmounted-used-by-one-pod",
  815. "/mnt/disks/vol2",
  816. base + `342 25 252:0 /mnt/disks/vol2 /mnt/disks/vol2 rw,relatime shared:1 - ext4 /dev/mapper/ubuntu--vg-root rw,errors=remount-ro,data=ordered
  817. 77 25 252:0 /mnt/disks/vol2 /var/lib/kubelet/pods/f30dc360-5a5d-11e8-962f-000c29bb0377/volumes/kubernetes.io~local-volume/local-pv-1fb30a1c rw,relatime shared:1 - ext4 /dev/mapper/ubuntu--vg-root rw,errors=remount-ro,data=ordered
  818. `,
  819. []string{"/var/lib/kubelet/pods/f30dc360-5a5d-11e8-962f-000c29bb0377/volumes/kubernetes.io~local-volume/local-pv-1fb30a1c"},
  820. nil,
  821. },
  822. {
  823. "blockfs",
  824. "/mnt/disks/blkvol1",
  825. base + `58 25 7:1 / /mnt/disks/blkvol1 rw,relatime shared:38 - ext4 /dev/loop1 rw,data=ordered
  826. `,
  827. nil,
  828. nil,
  829. },
  830. {
  831. "blockfs-used-by-one-pod",
  832. "/mnt/disks/blkvol1",
  833. base + `58 25 7:1 / /mnt/disks/blkvol1 rw,relatime shared:38 - ext4 /dev/loop1 rw,data=ordered
  834. 62 25 7:1 / /var/lib/kubelet/pods/f19fe4e2-5a63-11e8-962f-000c29bb0377/volumes/kubernetes.io~local-volume/local-pv-test rw,relatime shared:38 - ext4 /dev/loop1 rw,data=ordered
  835. `,
  836. []string{"/var/lib/kubelet/pods/f19fe4e2-5a63-11e8-962f-000c29bb0377/volumes/kubernetes.io~local-volume/local-pv-test"},
  837. nil,
  838. },
  839. {
  840. "blockfs-used-by-two-pods",
  841. "/mnt/disks/blkvol1",
  842. base + `58 25 7:1 / /mnt/disks/blkvol1 rw,relatime shared:38 - ext4 /dev/loop1 rw,data=ordered
  843. 62 25 7:1 / /var/lib/kubelet/pods/f19fe4e2-5a63-11e8-962f-000c29bb0377/volumes/kubernetes.io~local-volume/local-pv-test rw,relatime shared:38 - ext4 /dev/loop1 rw,data=ordered
  844. 95 25 7:1 / /var/lib/kubelet/pods/4854a48b-5a64-11e8-962f-000c29bb0377/volumes/kubernetes.io~local-volume/local-pv-test rw,relatime shared:38 - ext4 /dev/loop1 rw,data=ordered
  845. `,
  846. []string{"/var/lib/kubelet/pods/f19fe4e2-5a63-11e8-962f-000c29bb0377/volumes/kubernetes.io~local-volume/local-pv-test",
  847. "/var/lib/kubelet/pods/4854a48b-5a64-11e8-962f-000c29bb0377/volumes/kubernetes.io~local-volume/local-pv-test"},
  848. nil,
  849. },
  850. }
  851. tmpFile, err := ioutil.TempFile("", "test-get-filetype")
  852. if err != nil {
  853. t.Fatal(err)
  854. }
  855. defer os.Remove(tmpFile.Name())
  856. defer tmpFile.Close()
  857. for _, v := range testcases {
  858. tmpFile.Truncate(0)
  859. tmpFile.Seek(0, 0)
  860. tmpFile.WriteString(v.mountInfos)
  861. tmpFile.Sync()
  862. refs, err := SearchMountPoints(v.source, tmpFile.Name())
  863. if !reflect.DeepEqual(refs, v.expectedRefs) {
  864. t.Errorf("test %q: expected Refs: %#v, got %#v", v.name, v.expectedRefs, refs)
  865. }
  866. if !reflect.DeepEqual(err, v.expectedErr) {
  867. t.Errorf("test %q: expected err: %v, got %v", v.name, v.expectedErr, err)
  868. }
  869. }
  870. }