blob: 82007fade70105747455b519fc4a8e1223b71371 [file] [log] [blame]
Patrick Williams0ca19cc2021-08-16 14:03:13 -05001#
2# SPDX-License-Identifier: MIT
3#
4
5from oeqa.selftest.case import OESelftestTestCase
6from oeqa.utils.commands import runCmd, bitbake, get_bb_var, runqemu
7
Andrew Geissler595f6302022-01-24 19:11:47 +00008def getline_qemu(out, line):
9 for l in out.split('\n'):
10 if line in l:
11 return l
12
13def getline(res, line):
14 return getline_qemu(res.output, line)
15
Patrick Williams0ca19cc2021-08-16 14:03:13 -050016class OverlayFSTests(OESelftestTestCase):
17 """Overlayfs class usage tests"""
18
Patrick Williams0ca19cc2021-08-16 14:03:13 -050019 def add_overlay_conf_to_machine(self):
20 machine_inc = """
21OVERLAYFS_MOUNT_POINT[mnt-overlay] = "/mnt/overlay"
22"""
23 self.set_machine_config(machine_inc)
24
25 def test_distro_features_missing(self):
26 """
27 Summary: Check that required DISTRO_FEATURES are set
28 Expected: Fail when either systemd or overlayfs are not in DISTRO_FEATURES
29 Author: Vyacheslav Yurkov <uvv.mail@gmail.com>
30 """
31
32 config = """
33IMAGE_INSTALL:append = " overlayfs-user"
34"""
35 overlayfs_recipe_append = """
36inherit overlayfs
37"""
38 self.write_config(config)
39 self.add_overlay_conf_to_machine()
40 self.write_recipeinc('overlayfs-user', overlayfs_recipe_append)
41
42 res = bitbake('core-image-minimal', ignore_status=True)
Andrew Geissler595f6302022-01-24 19:11:47 +000043 line = getline(res, "overlayfs-user was skipped: missing required distro features")
Patrick Williams0ca19cc2021-08-16 14:03:13 -050044 self.assertTrue("overlayfs" in res.output, msg=res.output)
45 self.assertTrue("systemd" in res.output, msg=res.output)
46 self.assertTrue("ERROR: Required build target 'core-image-minimal' has no buildable providers." in res.output, msg=res.output)
47
48 def test_not_all_units_installed(self):
49 """
50 Summary: Test QA check that we have required mount units in the image
51 Expected: Fail because mount unit for overlay partition is not installed
52 Author: Vyacheslav Yurkov <uvv.mail@gmail.com>
53 """
54
55 config = """
56IMAGE_INSTALL:append = " overlayfs-user"
57DISTRO_FEATURES += "systemd overlayfs"
58"""
59
60 self.write_config(config)
61 self.add_overlay_conf_to_machine()
62
63 res = bitbake('core-image-minimal', ignore_status=True)
Andrew Geissler595f6302022-01-24 19:11:47 +000064 line = getline(res, "Unit name mnt-overlay.mount not found in systemd unit directories")
Patrick Williams0ca19cc2021-08-16 14:03:13 -050065 self.assertTrue(line and line.startswith("WARNING:"), msg=res.output)
Andrew Geissler595f6302022-01-24 19:11:47 +000066 line = getline(res, "Not all mount units are installed by the BSP")
Patrick Williams0ca19cc2021-08-16 14:03:13 -050067 self.assertTrue(line and line.startswith("ERROR:"), msg=res.output)
68
69 def test_mount_unit_not_set(self):
70 """
71 Summary: Test whether mount unit was set properly
72 Expected: Fail because mount unit was not set
73 Author: Vyacheslav Yurkov <uvv.mail@gmail.com>
74 """
75
76 config = """
77IMAGE_INSTALL:append = " overlayfs-user"
78DISTRO_FEATURES += "systemd overlayfs"
79"""
80
81 self.write_config(config)
82
83 res = bitbake('core-image-minimal', ignore_status=True)
Andrew Geissler595f6302022-01-24 19:11:47 +000084 line = getline(res, "A recipe uses overlayfs class but there is no OVERLAYFS_MOUNT_POINT set in your MACHINE configuration")
Patrick Williams0ca19cc2021-08-16 14:03:13 -050085 self.assertTrue(line and line.startswith("Parsing recipes...ERROR:"), msg=res.output)
86
87 def test_wrong_mount_unit_set(self):
88 """
89 Summary: Test whether mount unit was set properly
90 Expected: Fail because not the correct flag used for mount unit
91 Author: Vyacheslav Yurkov <uvv.mail@gmail.com>
92 """
93
94 config = """
95IMAGE_INSTALL:append = " overlayfs-user"
96DISTRO_FEATURES += "systemd overlayfs"
97"""
98
99 wrong_machine_config = """
100OVERLAYFS_MOUNT_POINT[usr-share-overlay] = "/usr/share/overlay"
101"""
102
103 self.write_config(config)
104 self.set_machine_config(wrong_machine_config)
105
106 res = bitbake('core-image-minimal', ignore_status=True)
Andrew Geissler595f6302022-01-24 19:11:47 +0000107 line = getline(res, "Missing required mount point for OVERLAYFS_MOUNT_POINT[mnt-overlay] in your MACHINE configuration")
Patrick Williams0ca19cc2021-08-16 14:03:13 -0500108 self.assertTrue(line and line.startswith("Parsing recipes...ERROR:"), msg=res.output)
109
110 def test_correct_image(self):
111 """
112 Summary: Check that we can create an image when all parameters are
113 set correctly
114 Expected: Image is created successfully
115 Author: Vyacheslav Yurkov <uvv.mail@gmail.com>
116 """
117
118 config = """
119IMAGE_INSTALL:append = " overlayfs-user systemd-machine-units"
120DISTRO_FEATURES += "systemd overlayfs"
121
122# Use systemd as init manager
123VIRTUAL-RUNTIME_init_manager = "systemd"
124
125# enable overlayfs in the kernel
126KERNEL_EXTRA_FEATURES:append = " features/overlayfs/overlayfs.scc"
127"""
128
129 systemd_machine_unit_append = """
130SYSTEMD_SERVICE:${PN} += " \
131 mnt-overlay.mount \
132"
133
134do_install:append() {
135 install -d ${D}${systemd_system_unitdir}
136 cat <<EOT > ${D}${systemd_system_unitdir}/mnt-overlay.mount
137[Unit]
138Description=Tmpfs directory
139DefaultDependencies=no
140
141[Mount]
142What=tmpfs
143Where=/mnt/overlay
144Type=tmpfs
145Options=mode=1777,strictatime,nosuid,nodev
146
147[Install]
148WantedBy=multi-user.target
149EOT
150}
151
152"""
153
Andrew Geissler595f6302022-01-24 19:11:47 +0000154 overlayfs_recipe_append = """
155OVERLAYFS_WRITABLE_PATHS[mnt-overlay] += "/usr/share/another-overlay-mount"
156
157SYSTEMD_SERVICE:${PN} += " \
158 my-application.service \
159"
160
161do_install:append() {
162 install -d ${D}${systemd_system_unitdir}
163 cat <<EOT > ${D}${systemd_system_unitdir}/my-application.service
164[Unit]
165Description=Sample application start-up unit
166After=overlayfs-user-overlays.service
167Requires=overlayfs-user-overlays.service
168
169[Service]
170Type=oneshot
171ExecStart=/bin/true
172RemainAfterExit=true
173
174[Install]
175WantedBy=multi-user.target
176EOT
177}
178"""
179
Patrick Williams0ca19cc2021-08-16 14:03:13 -0500180 self.write_config(config)
181 self.add_overlay_conf_to_machine()
182 self.write_recipeinc('systemd-machine-units', systemd_machine_unit_append)
Andrew Geissler595f6302022-01-24 19:11:47 +0000183 self.write_recipeinc('overlayfs-user', overlayfs_recipe_append)
Patrick Williams0ca19cc2021-08-16 14:03:13 -0500184
185 bitbake('core-image-minimal')
186
Patrick Williams0ca19cc2021-08-16 14:03:13 -0500187 with runqemu('core-image-minimal') as qemu:
Andrew Geissler595f6302022-01-24 19:11:47 +0000188 # Check that application service started
189 status, output = qemu.run_serial("systemctl status my-application")
190 self.assertTrue("active (exited)" in output, msg=output)
191
192 # Check that overlay mounts are dependencies of our application unit
193 status, output = qemu.run_serial("systemctl list-dependencies my-application")
194 self.assertTrue("overlayfs-user-overlays.service" in output, msg=output)
195
196 status, output = qemu.run_serial("systemctl list-dependencies overlayfs-user-overlays")
197 self.assertTrue("usr-share-another\\x2doverlay\\x2dmount.mount" in output, msg=output)
198 self.assertTrue("usr-share-my\\x2dapplication.mount" in output, msg=output)
199
Patrick Williams0ca19cc2021-08-16 14:03:13 -0500200 # Check that we have /mnt/overlay fs mounted as tmpfs and
201 # /usr/share/my-application as an overlay (see overlayfs-user recipe)
202 status, output = qemu.run_serial("/bin/mount -t tmpfs,overlay")
203
204 line = getline_qemu(output, "on /mnt/overlay")
205 self.assertTrue(line and line.startswith("tmpfs"), msg=output)
206
207 line = getline_qemu(output, "upperdir=/mnt/overlay/upper/usr/share/my-application")
208 self.assertTrue(line and line.startswith("overlay"), msg=output)
Andrew Geissler595f6302022-01-24 19:11:47 +0000209
210 line = getline_qemu(output, "upperdir=/mnt/overlay/upper/usr/share/another-overlay-mount")
211 self.assertTrue(line and line.startswith("overlay"), msg=output)
212
213class OverlayFSEtcRunTimeTests(OESelftestTestCase):
214 """overlayfs-etc class tests"""
215
216 def test_all_required_variables_set(self):
217 """
218 Summary: Check that required variables are set
219 Expected: Fail when any of required variables is missing
220 Author: Vyacheslav Yurkov <uvv.mail@gmail.com>
221 """
222
223 configBase = """
224DISTRO_FEATURES += "systemd"
225
226# Use systemd as init manager
227VIRTUAL-RUNTIME_init_manager = "systemd"
228
229# enable overlayfs in the kernel
230KERNEL_EXTRA_FEATURES:append = " features/overlayfs/overlayfs.scc"
231
232# Image configuration for overlayfs-etc
233EXTRA_IMAGE_FEATURES += "overlayfs-etc"
234IMAGE_FEATURES:remove = "package-management"
235"""
236 configMountPoint = """
237OVERLAYFS_ETC_MOUNT_POINT = "/data"
238"""
239 configDevice = """
240OVERLAYFS_ETC_DEVICE = "/dev/mmcblk0p1"
241"""
242
243 self.write_config(configBase)
244 res = bitbake('core-image-minimal', ignore_status=True)
245 line = getline(res, "OVERLAYFS_ETC_MOUNT_POINT must be set in your MACHINE configuration")
246 self.assertTrue(line, msg=res.output)
247
248 self.append_config(configMountPoint)
249 res = bitbake('core-image-minimal', ignore_status=True)
250 line = getline(res, "OVERLAYFS_ETC_DEVICE must be set in your MACHINE configuration")
251 self.assertTrue(line, msg=res.output)
252
253 self.append_config(configDevice)
254 res = bitbake('core-image-minimal', ignore_status=True)
255 line = getline(res, "OVERLAYFS_ETC_FSTYPE should contain a valid file system type on /dev/mmcblk0p1")
256 self.assertTrue(line, msg=res.output)
257
258 def test_image_feature_conflict(self):
259 """
260 Summary: Overlayfs-etc is not allowed to be used with package-management
261 Expected: Feature conflict
262 Author: Vyacheslav Yurkov <uvv.mail@gmail.com>
263 """
264
265 config = """
266DISTRO_FEATURES += "systemd"
267
268# Use systemd as init manager
269VIRTUAL-RUNTIME_init_manager = "systemd"
270
271# enable overlayfs in the kernel
272KERNEL_EXTRA_FEATURES:append = " features/overlayfs/overlayfs.scc"
273EXTRA_IMAGE_FEATURES += "overlayfs-etc"
274EXTRA_IMAGE_FEATURES += "package-management"
275"""
276
277 self.write_config(config)
278
279 res = bitbake('core-image-minimal', ignore_status=True)
280 line = getline(res, "contains conflicting IMAGE_FEATURES")
281 self.assertTrue("overlayfs-etc" in res.output, msg=res.output)
282 self.assertTrue("package-management" in res.output, msg=res.output)
283
284 def test_image_feature_is_missing_class_included(self):
285 configAppend = """
286INHERIT += "overlayfs-etc"
287"""
288 self.run_check_image_feature(configAppend)
289
290 def test_image_feature_is_missing(self):
291 self.run_check_image_feature()
292
293 def run_check_image_feature(self, appendToConfig=""):
294 """
295 Summary: Overlayfs-etc class is not applied when image feature is not set
296 even if we inherit it directly,
297 Expected: Image is created successfully but /etc is not an overlay
298 Author: Vyacheslav Yurkov <uvv.mail@gmail.com>
299 """
300
301 config = f"""
302DISTRO_FEATURES += "systemd"
303
304# Use systemd as init manager
305VIRTUAL-RUNTIME_init_manager = "systemd"
306
307# enable overlayfs in the kernel
308KERNEL_EXTRA_FEATURES:append = " features/overlayfs/overlayfs.scc"
309
310IMAGE_FSTYPES += "wic"
311WKS_FILE = "overlayfs_etc.wks.in"
312
313EXTRA_IMAGE_FEATURES += "read-only-rootfs"
314# Image configuration for overlayfs-etc
315OVERLAYFS_ETC_MOUNT_POINT = "/data"
316OVERLAYFS_ETC_DEVICE = "/dev/sda3"
317{appendToConfig}
318"""
319
320 self.write_config(config)
321
322 bitbake('core-image-minimal')
323
324 with runqemu('core-image-minimal', image_fstype='wic') as qemu:
325 status, output = qemu.run_serial("/bin/mount")
326
327 line = getline_qemu(output, "upperdir=/data/overlay-etc/upper")
328 self.assertFalse(line, msg=output)
329
330 def test_sbin_init_preinit(self):
331 self.run_sbin_init(False)
332
333 def test_sbin_init_original(self):
334 self.run_sbin_init(True)
335
336 def run_sbin_init(self, origInit):
337 """
338 Summary: Confirm we can replace original init and mount overlay on top of /etc
339 Expected: Image is created successfully and /etc is mounted as an overlay
340 Author: Vyacheslav Yurkov <uvv.mail@gmail.com>
341 """
342
343 config = """
344DISTRO_FEATURES += "systemd"
345
346# Use systemd as init manager
347VIRTUAL-RUNTIME_init_manager = "systemd"
348
349# enable overlayfs in the kernel
350KERNEL_EXTRA_FEATURES:append = " features/overlayfs/overlayfs.scc"
351
352IMAGE_FSTYPES += "wic"
353OVERLAYFS_INIT_OPTION = "{OVERLAYFS_INIT_OPTION}"
354WKS_FILE = "overlayfs_etc.wks.in"
355
356EXTRA_IMAGE_FEATURES += "read-only-rootfs"
357# Image configuration for overlayfs-etc
358EXTRA_IMAGE_FEATURES += "overlayfs-etc"
359IMAGE_FEATURES:remove = "package-management"
360OVERLAYFS_ETC_MOUNT_POINT = "/data"
361OVERLAYFS_ETC_FSTYPE = "ext4"
362OVERLAYFS_ETC_DEVICE = "/dev/sda3"
363OVERLAYFS_ETC_USE_ORIG_INIT_NAME = "{OVERLAYFS_ETC_USE_ORIG_INIT_NAME}"
364"""
365
366 args = {
367 'OVERLAYFS_INIT_OPTION': "" if origInit else "init=/sbin/preinit",
368 'OVERLAYFS_ETC_USE_ORIG_INIT_NAME': int(origInit == True)
369 }
370
371 self.write_config(config.format(**args))
372
373 bitbake('core-image-minimal')
374 testFile = "/etc/my-test-data"
375
376 with runqemu('core-image-minimal', image_fstype='wic', discard_writes=False) as qemu:
377 status, output = qemu.run_serial("/bin/mount")
378
379 line = getline_qemu(output, "/dev/sda3")
380 self.assertTrue("/data" in output, msg=output)
381
382 line = getline_qemu(output, "upperdir=/data/overlay-etc/upper")
383 self.assertTrue(line and line.startswith("/data/overlay-etc/upper on /etc type overlay"), msg=output)
384
385 status, output = qemu.run_serial("touch " + testFile)
386 status, output = qemu.run_serial("sync")
387 status, output = qemu.run_serial("ls -1 " + testFile)
388 line = getline_qemu(output, testFile)
389 self.assertTrue(line and line.startswith(testFile), msg=output)
390
391 # Check that file exists in /etc after reboot
392 with runqemu('core-image-minimal', image_fstype='wic') as qemu:
393 status, output = qemu.run_serial("ls -1 " + testFile)
394 line = getline_qemu(output, testFile)
395 self.assertTrue(line and line.startswith(testFile), msg=output)