1// +build !windows
2
3/*
4Copyright 2019 The Kubernetes Authors.
5
6Licensed under the Apache License, Version 2.0 (the "License");
7you may not use this file except in compliance with the License.
8You may obtain a copy of the License at
9
10    http://www.apache.org/licenses/LICENSE-2.0
11
12Unless required by applicable law or agreed to in writing, software
13distributed under the License is distributed on an "AS IS" BASIS,
14WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15See the License for the specific language governing permissions and
16limitations under the License.
17*/
18
19package mount
20
21import (
22	"io/ioutil"
23	"os"
24	"path/filepath"
25	"reflect"
26	"testing"
27)
28
29func writeFile(content string) (string, string, error) {
30	tempDir, err := ioutil.TempDir("", "mounter_shared_test")
31	if err != nil {
32		return "", "", err
33	}
34	filename := filepath.Join(tempDir, "mountinfo")
35	err = ioutil.WriteFile(filename, []byte(content), 0600)
36	if err != nil {
37		os.RemoveAll(tempDir)
38		return "", "", err
39	}
40	return tempDir, filename, nil
41}
42
43func TestParseMountInfo(t *testing.T) {
44	info :=
45		`62 0 253:0 / / rw,relatime shared:1 - ext4 /dev/mapper/ssd-root rw,seclabel,data=ordered
4678 62 0:41 / /tmp rw,nosuid,nodev shared:30 - tmpfs tmpfs rw,seclabel
4780 62 0:42 / /var/lib/nfs/rpc_pipefs rw,relatime shared:31 - rpc_pipefs sunrpc rw
4882 62 0:43 / /var/lib/foo rw,relatime shared:32 - tmpfs tmpfs rw
4983 63 0:44 / /var/lib/bar rw,relatime - tmpfs tmpfs rw
50227 62 253:0 /var/lib/docker/devicemapper /var/lib/docker/devicemapper rw,relatime - ext4 /dev/mapper/ssd-root rw,seclabel,data=ordered
51224 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
5276 17 8:1 / /mnt/stateful_partition rw,nosuid,nodev,noexec,relatime - ext4 /dev/sda1 rw,commit=30,data=ordered
5380 17 8:1 /var /var rw,nosuid,nodev,noexec,relatime shared:30 - ext4 /dev/sda1 rw,commit=30,data=ordered
54189 80 8:1 /var/lib/kubelet /var/lib/kubelet rw,relatime shared:30 - ext4 /dev/sda1 rw,commit=30,data=ordered
55818 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
56819 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
57900 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
58901 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
59902 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
60903 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
61178 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
62698 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
63918 77 8:50 / /var/lib/kubelet/pods/2345/volumes/kubernetes.io~gce-pd/vol1 rw,relatime shared:290 - ext4 /dev/sdc rw,data=ordered
64919 78 8:58 / /var/lib/kubelet/pods/2345/volumes/kubernetes.io~gce-pd/vol1 rw,relatime shared:290 - ext4 /dev/sdd rw,data=ordered
65920 100 8:50 /dir1 /var/lib/kubelet/pods/2345/volume-subpaths/vol1/subpath1/0 rw,relatime shared:290 - ext4 /dev/sdc rw,data=ordered
66150 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
67151 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
68134 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
69187 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
70188 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
71347 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
72222 24 253:0 /tmp/src /mnt/dst rw,relatime shared:1 - ext4 /dev/mapper/vagrant--vg-root rw,errors=remount-ro,data=ordered
7328 18 0:24 / /sys/fs/cgroup ro,nosuid,nodev,noexec shared:9 - tmpfs tmpfs ro,mode=755
7429 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
7531 28 0:27 / /sys/fs/cgroup/cpuset rw,nosuid,nodev,noexec,relatime shared:13 - cgroup cgroup rw,cpuset
7632 28 0:28 / /sys/fs/cgroup/cpu,cpuacct rw,nosuid,nodev,noexec,relatime shared:14 - cgroup cgroup rw,cpu,cpuacct
7733 28 0:29 / /sys/fs/cgroup/freezer rw,nosuid,nodev,noexec,relatime shared:15 - cgroup cgroup rw,freezer
7834 28 0:30 / /sys/fs/cgroup/net_cls,net_prio rw,nosuid,nodev,noexec,relatime shared:16 - cgroup cgroup rw,net_cls,net_prio
7935 28 0:31 / /sys/fs/cgroup/pids rw,nosuid,nodev,noexec,relatime shared:17 - cgroup cgroup rw,pids
8036 28 0:32 / /sys/fs/cgroup/devices rw,nosuid,nodev,noexec,relatime shared:18 - cgroup cgroup rw,devices
8137 28 0:33 / /sys/fs/cgroup/hugetlb rw,nosuid,nodev,noexec,relatime shared:19 - cgroup cgroup rw,hugetlb
8238 28 0:34 / /sys/fs/cgroup/blkio rw,nosuid,nodev,noexec,relatime shared:20 - cgroup cgroup rw,blkio
8339 28 0:35 / /sys/fs/cgroup/memory rw,nosuid,nodev,noexec,relatime shared:21 - cgroup cgroup rw,memory
8440 28 0:36 / /sys/fs/cgroup/perf_event rw,nosuid,nodev,noexec,relatime shared:22 - cgroup cgroup rw,perf_event
85`
86	tempDir, filename, err := writeFile(info)
87	if err != nil {
88		t.Fatalf("cannot create temporary file: %v", err)
89	}
90	defer os.RemoveAll(tempDir)
91
92	tests := []struct {
93		name         string
94		id           int
95		expectedInfo MountInfo
96	}{
97		{
98			"simple bind mount",
99			189,
100			MountInfo{
101				ID:             189,
102				ParentID:       80,
103				MajorMinor:     "8:1",
104				Root:           "/var/lib/kubelet",
105				Source:         "/dev/sda1",
106				MountPoint:     "/var/lib/kubelet",
107				OptionalFields: []string{"shared:30"},
108				FsType:         "ext4",
109				MountOptions:   []string{"rw", "relatime"},
110				SuperOptions:   []string{"rw", "commit=30", "data=ordered"},
111			},
112		},
113		{
114			"bind mount a directory",
115			222,
116			MountInfo{
117				ID:             222,
118				ParentID:       24,
119				MajorMinor:     "253:0",
120				Root:           "/tmp/src",
121				Source:         "/dev/mapper/vagrant--vg-root",
122				MountPoint:     "/mnt/dst",
123				OptionalFields: []string{"shared:1"},
124				FsType:         "ext4",
125				MountOptions:   []string{"rw", "relatime"},
126				SuperOptions:   []string{"rw", "errors=remount-ro", "data=ordered"},
127			},
128		},
129		{
130			"more than one optional fields",
131			224,
132			MountInfo{
133				ID:             224,
134				ParentID:       62,
135				MajorMinor:     "253:0",
136				Root:           "/var/lib/docker/devicemapper/test/shared",
137				Source:         "/dev/mapper/ssd-root",
138				MountPoint:     "/var/lib/docker/devicemapper/test/shared",
139				OptionalFields: []string{"master:1", "shared:44"},
140				FsType:         "ext4",
141				MountOptions:   []string{"rw", "relatime"},
142				SuperOptions:   []string{"rw", "seclabel", "data=ordered"},
143			},
144		},
145		{
146			"cgroup-mountpoint",
147			28,
148			MountInfo{
149				ID:             28,
150				ParentID:       18,
151				MajorMinor:     "0:24",
152				Root:           "/",
153				Source:         "tmpfs",
154				MountPoint:     "/sys/fs/cgroup",
155				OptionalFields: []string{"shared:9"},
156				FsType:         "tmpfs",
157				MountOptions:   []string{"ro", "nosuid", "nodev", "noexec"},
158				SuperOptions:   []string{"ro", "mode=755"},
159			},
160		},
161		{
162			"cgroup-subsystem-systemd-mountpoint",
163			29,
164			MountInfo{
165				ID:             29,
166				ParentID:       28,
167				MajorMinor:     "0:25",
168				Root:           "/",
169				Source:         "cgroup",
170				MountPoint:     "/sys/fs/cgroup/systemd",
171				OptionalFields: []string{"shared:10"},
172				FsType:         "cgroup",
173				MountOptions:   []string{"rw", "nosuid", "nodev", "noexec", "relatime"},
174				SuperOptions:   []string{"rw", "xattr", "release_agent=/lib/systemd/systemd-cgroups-agent", "name=systemd"},
175			},
176		},
177		{
178			"cgroup-subsystem-cpuset-mountpoint",
179			31,
180			MountInfo{
181				ID:             31,
182				ParentID:       28,
183				MajorMinor:     "0:27",
184				Root:           "/",
185				Source:         "cgroup",
186				MountPoint:     "/sys/fs/cgroup/cpuset",
187				OptionalFields: []string{"shared:13"},
188				FsType:         "cgroup",
189				MountOptions:   []string{"rw", "nosuid", "nodev", "noexec", "relatime"},
190				SuperOptions:   []string{"rw", "cpuset"},
191			},
192		},
193	}
194
195	infos, err := ParseMountInfo(filename)
196	if err != nil {
197		t.Fatalf("Cannot parse %s: %s", filename, err)
198	}
199
200	for _, test := range tests {
201		found := false
202		for _, info := range infos {
203			if info.ID == test.id {
204				found = true
205				if !reflect.DeepEqual(info, test.expectedInfo) {
206					t.Errorf("Test case %q:\n expected: %+v\n got:      %+v", test.name, test.expectedInfo, info)
207				}
208				break
209			}
210		}
211		if !found {
212			t.Errorf("Test case %q: mountPoint %d not found", test.name, test.id)
213		}
214	}
215}
216