wic.py 89 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909
  1. #
  2. # Copyright (c) 2015, Intel Corporation.
  3. #
  4. # SPDX-License-Identifier: GPL-2.0-only
  5. #
  6. # AUTHORS
  7. # Ed Bartosh <ed.bartosh@linux.intel.com>
  8. """Test cases for wic."""
  9. import os
  10. import sys
  11. import unittest
  12. import hashlib
  13. import subprocess
  14. from glob import glob
  15. from shutil import rmtree, copy
  16. from tempfile import NamedTemporaryFile
  17. from tempfile import TemporaryDirectory
  18. from oeqa.selftest.case import OESelftestTestCase
  19. from oeqa.core.decorator import OETestTag
  20. from oeqa.core.decorator.data import skipIfNotArch
  21. from oeqa.utils.commands import runCmd, bitbake, get_bb_var, get_bb_vars, runqemu
  22. def extract_files(debugfs_output):
  23. """
  24. extract file names from the output of debugfs -R 'ls -p',
  25. which looks like this:
  26. /2/040755/0/0/.//\n
  27. /2/040755/0/0/..//\n
  28. /11/040700/0/0/lost+found^M//\n
  29. /12/040755/1002/1002/run//\n
  30. /13/040755/1002/1002/sys//\n
  31. /14/040755/1002/1002/bin//\n
  32. /80/040755/1002/1002/var//\n
  33. /92/040755/1002/1002/tmp//\n
  34. """
  35. # NOTE the occasional ^M in file names
  36. return [line.split('/')[5].strip() for line in \
  37. debugfs_output.strip().split('/\n')]
  38. def files_own_by_root(debugfs_output):
  39. for line in debugfs_output.strip().split('/\n'):
  40. if line.split('/')[3:5] != ['0', '0']:
  41. print(debugfs_output)
  42. return False
  43. return True
  44. class WicTestCase(OESelftestTestCase):
  45. """Wic test class."""
  46. image_is_ready = False
  47. wicenv_cache = {}
  48. def setUpLocal(self):
  49. """This code is executed before each test method."""
  50. self.resultdir = os.path.join(self.builddir, "wic-tmp")
  51. super(WicTestCase, self).setUpLocal()
  52. # Do this here instead of in setUpClass as the base setUp does some
  53. # clean up which can result in the native tools built earlier in
  54. # setUpClass being unavailable.
  55. if not WicTestCase.image_is_ready:
  56. if self.td['USE_NLS'] != 'yes':
  57. self.skipTest('wic-tools needs USE_NLS=yes')
  58. bitbake('wic-tools core-image-minimal core-image-minimal-mtdutils')
  59. WicTestCase.image_is_ready = True
  60. rmtree(self.resultdir, ignore_errors=True)
  61. def tearDownLocal(self):
  62. """Remove resultdir as it may contain images."""
  63. rmtree(self.resultdir, ignore_errors=True)
  64. super(WicTestCase, self).tearDownLocal()
  65. def _get_image_env_path(self, image):
  66. """Generate and obtain the path to <image>.env"""
  67. if image not in WicTestCase.wicenv_cache:
  68. bitbake('%s -c do_rootfs_wicenv' % image)
  69. stdir = get_bb_var('STAGING_DIR', image)
  70. machine = self.td["MACHINE"]
  71. WicTestCase.wicenv_cache[image] = os.path.join(stdir, machine, 'imgdata')
  72. return WicTestCase.wicenv_cache[image]
  73. class CLITests(OESelftestTestCase):
  74. def test_version(self):
  75. """Test wic --version"""
  76. runCmd('wic --version')
  77. def test_help(self):
  78. """Test wic --help and wic -h"""
  79. runCmd('wic --help')
  80. runCmd('wic -h')
  81. def test_createhelp(self):
  82. """Test wic create --help"""
  83. runCmd('wic create --help')
  84. def test_listhelp(self):
  85. """Test wic list --help"""
  86. runCmd('wic list --help')
  87. def test_help_create(self):
  88. """Test wic help create"""
  89. runCmd('wic help create')
  90. def test_help_list(self):
  91. """Test wic help list"""
  92. runCmd('wic help list')
  93. def test_help_overview(self):
  94. """Test wic help overview"""
  95. runCmd('wic help overview')
  96. def test_help_plugins(self):
  97. """Test wic help plugins"""
  98. runCmd('wic help plugins')
  99. def test_help_kickstart(self):
  100. """Test wic help kickstart"""
  101. runCmd('wic help kickstart')
  102. def test_list_images(self):
  103. """Test wic list images"""
  104. runCmd('wic list images')
  105. def test_list_source_plugins(self):
  106. """Test wic list source-plugins"""
  107. runCmd('wic list source-plugins')
  108. def test_listed_images_help(self):
  109. """Test wic listed images help"""
  110. output = runCmd('wic list images').output
  111. imagelist = [line.split()[0] for line in output.splitlines()]
  112. for image in imagelist:
  113. runCmd('wic list %s help' % image)
  114. def test_unsupported_subcommand(self):
  115. """Test unsupported subcommand"""
  116. self.assertNotEqual(0, runCmd('wic unsupported', ignore_status=True).status)
  117. def test_no_command(self):
  118. """Test wic without command"""
  119. self.assertEqual(1, runCmd('wic', ignore_status=True).status)
  120. class Wic(WicTestCase):
  121. def test_skip_kernel_install(self):
  122. """Test the functionality of not installing the kernel in the boot directory using the wic plugin"""
  123. # create a temporary file for the WKS content
  124. with NamedTemporaryFile("w", suffix=".wks") as wks:
  125. wks.write(
  126. 'part --source bootimg-efi '
  127. '--sourceparams="loader=grub-efi,install-kernel-into-boot-dir=false" '
  128. '--label boot --active\n'
  129. )
  130. wks.flush()
  131. # create a temporary directory to extract the disk image to
  132. with TemporaryDirectory() as tmpdir:
  133. img = 'core-image-minimal'
  134. # build the image using the WKS file
  135. cmd = "wic create %s -e %s -o %s" % (
  136. wks.name, img, self.resultdir)
  137. runCmd(cmd)
  138. wksname = os.path.splitext(os.path.basename(wks.name))[0]
  139. out = glob(os.path.join(
  140. self.resultdir, "%s-*.direct" % wksname))
  141. self.assertEqual(1, len(out))
  142. sysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'wic-tools')
  143. # extract the content of the disk image to the temporary directory
  144. cmd = "wic cp %s:1 %s -n %s" % (out[0], tmpdir, sysroot)
  145. runCmd(cmd)
  146. # check if the kernel is installed or not
  147. kimgtype = get_bb_var('KERNEL_IMAGETYPE', img)
  148. for file in os.listdir(tmpdir):
  149. if file == kimgtype:
  150. raise AssertionError(
  151. "The kernel image '{}' was found in the partition".format(kimgtype)
  152. )
  153. def test_kernel_install(self):
  154. """Test the installation of the kernel to the boot directory in the wic plugin"""
  155. # create a temporary file for the WKS content
  156. with NamedTemporaryFile("w", suffix=".wks") as wks:
  157. wks.write(
  158. 'part --source bootimg-efi '
  159. '--sourceparams="loader=grub-efi,install-kernel-into-boot-dir=true" '
  160. '--label boot --active\n'
  161. )
  162. wks.flush()
  163. # create a temporary directory to extract the disk image to
  164. with TemporaryDirectory() as tmpdir:
  165. img = 'core-image-minimal'
  166. # build the image using the WKS file
  167. cmd = "wic create %s -e %s -o %s" % (wks.name, img, self.resultdir)
  168. runCmd(cmd)
  169. wksname = os.path.splitext(os.path.basename(wks.name))[0]
  170. out = glob(os.path.join(self.resultdir, "%s-*.direct" % wksname))
  171. self.assertEqual(1, len(out))
  172. sysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'wic-tools')
  173. # extract the content of the disk image to the temporary directory
  174. cmd = "wic cp %s:1 %s -n %s" % (out[0], tmpdir, sysroot)
  175. runCmd(cmd)
  176. # check if the kernel is installed or not
  177. kimgtype = get_bb_var('KERNEL_IMAGETYPE', img)
  178. found = False
  179. for file in os.listdir(tmpdir):
  180. if file == kimgtype:
  181. found = True
  182. break
  183. self.assertTrue(
  184. found, "The kernel image '{}' was not found in the boot partition".format(kimgtype)
  185. )
  186. def test_build_image_name(self):
  187. """Test wic create wictestdisk --image-name=core-image-minimal"""
  188. cmd = "wic create wictestdisk --image-name=core-image-minimal -o %s" % self.resultdir
  189. runCmd(cmd)
  190. self.assertEqual(1, len(glob(os.path.join (self.resultdir, "wictestdisk-*.direct"))))
  191. @skipIfNotArch(['i586', 'i686', 'x86_64'])
  192. def test_gpt_image(self):
  193. """Test creation of core-image-minimal with gpt table and UUID boot"""
  194. cmd = "wic create directdisk-gpt --image-name core-image-minimal -o %s" % self.resultdir
  195. runCmd(cmd)
  196. self.assertEqual(1, len(glob(os.path.join(self.resultdir, "directdisk-*.direct"))))
  197. @skipIfNotArch(['i586', 'i686', 'x86_64'])
  198. def test_iso_image(self):
  199. """Test creation of hybrid iso image with legacy and EFI boot"""
  200. config = 'INITRAMFS_IMAGE = "core-image-minimal-initramfs"\n'\
  201. 'MACHINE_FEATURES:append = " efi"\n'\
  202. 'DEPENDS:pn-core-image-minimal += "syslinux"\n'
  203. self.append_config(config)
  204. bitbake('core-image-minimal core-image-minimal-initramfs')
  205. self.remove_config(config)
  206. cmd = "wic create mkhybridiso --image-name core-image-minimal -o %s" % self.resultdir
  207. runCmd(cmd)
  208. self.assertEqual(1, len(glob(os.path.join(self.resultdir, "HYBRID_ISO_IMG-*.direct"))))
  209. self.assertEqual(1, len(glob(os.path.join (self.resultdir, "HYBRID_ISO_IMG-*.iso"))))
  210. @skipIfNotArch(['i586', 'i686', 'x86_64'])
  211. def test_qemux86_directdisk(self):
  212. """Test creation of qemux-86-directdisk image"""
  213. cmd = "wic create qemux86-directdisk -e core-image-minimal -o %s" % self.resultdir
  214. runCmd(cmd)
  215. self.assertEqual(1, len(glob(os.path.join(self.resultdir, "qemux86-directdisk-*direct"))))
  216. @skipIfNotArch(['i586', 'i686', 'x86_64', 'aarch64'])
  217. def test_mkefidisk(self):
  218. """Test creation of mkefidisk image"""
  219. cmd = "wic create mkefidisk -e core-image-minimal -o %s" % self.resultdir
  220. runCmd(cmd)
  221. self.assertEqual(1, len(glob(os.path.join(self.resultdir, "mkefidisk-*direct"))))
  222. @skipIfNotArch(['i586', 'i686', 'x86_64'])
  223. def test_bootloader_config(self):
  224. """Test creation of directdisk-bootloader-config image"""
  225. config = 'DEPENDS:pn-core-image-minimal += "syslinux"\n'
  226. self.append_config(config)
  227. bitbake('core-image-minimal')
  228. self.remove_config(config)
  229. cmd = "wic create directdisk-bootloader-config -e core-image-minimal -o %s" % self.resultdir
  230. runCmd(cmd)
  231. self.assertEqual(1, len(glob(os.path.join(self.resultdir, "directdisk-bootloader-config-*direct"))))
  232. @skipIfNotArch(['i586', 'i686', 'x86_64', 'aarch64'])
  233. def test_systemd_bootdisk(self):
  234. """Test creation of systemd-bootdisk image"""
  235. config = 'MACHINE_FEATURES:append = " efi"\n'
  236. self.append_config(config)
  237. bitbake('core-image-minimal')
  238. self.remove_config(config)
  239. cmd = "wic create systemd-bootdisk -e core-image-minimal -o %s" % self.resultdir
  240. runCmd(cmd)
  241. self.assertEqual(1, len(glob(os.path.join(self.resultdir, "systemd-bootdisk-*direct"))))
  242. def test_efi_bootpart(self):
  243. """Test creation of efi-bootpart image"""
  244. cmd = "wic create mkefidisk -e core-image-minimal -o %s" % self.resultdir
  245. kimgtype = get_bb_var('KERNEL_IMAGETYPE', 'core-image-minimal')
  246. self.append_config('IMAGE_EFI_BOOT_FILES = "%s;kernel"\n' % kimgtype)
  247. runCmd(cmd)
  248. sysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'wic-tools')
  249. images = glob(os.path.join(self.resultdir, "mkefidisk-*.direct"))
  250. result = runCmd("wic ls %s:1/ -n %s" % (images[0], sysroot))
  251. self.assertIn("kernel",result.output)
  252. def test_sdimage_bootpart(self):
  253. """Test creation of sdimage-bootpart image"""
  254. cmd = "wic create sdimage-bootpart -e core-image-minimal -o %s" % self.resultdir
  255. kimgtype = get_bb_var('KERNEL_IMAGETYPE', 'core-image-minimal')
  256. self.write_config('IMAGE_BOOT_FILES = "%s"\n' % kimgtype)
  257. runCmd(cmd)
  258. self.assertEqual(1, len(glob(os.path.join(self.resultdir, "sdimage-bootpart-*direct"))))
  259. # TODO this doesn't have to be x86-specific
  260. @skipIfNotArch(['i586', 'i686', 'x86_64'])
  261. def test_default_output_dir(self):
  262. """Test default output location"""
  263. for fname in glob("directdisk-*.direct"):
  264. os.remove(fname)
  265. config = 'DEPENDS:pn-core-image-minimal += "syslinux"\n'
  266. self.append_config(config)
  267. bitbake('core-image-minimal')
  268. self.remove_config(config)
  269. cmd = "wic create directdisk -e core-image-minimal"
  270. runCmd(cmd)
  271. self.assertEqual(1, len(glob("directdisk-*.direct")))
  272. @skipIfNotArch(['i586', 'i686', 'x86_64'])
  273. def test_build_artifacts(self):
  274. """Test wic create directdisk providing all artifacts."""
  275. bb_vars = get_bb_vars(['STAGING_DATADIR', 'RECIPE_SYSROOT_NATIVE'],
  276. 'wic-tools')
  277. bb_vars.update(get_bb_vars(['DEPLOY_DIR_IMAGE', 'IMAGE_ROOTFS'],
  278. 'core-image-minimal'))
  279. bbvars = {key.lower(): value for key, value in bb_vars.items()}
  280. bbvars['resultdir'] = self.resultdir
  281. runCmd("wic create directdisk "
  282. "-b %(staging_datadir)s "
  283. "-k %(deploy_dir_image)s "
  284. "-n %(recipe_sysroot_native)s "
  285. "-r %(image_rootfs)s "
  286. "-o %(resultdir)s" % bbvars)
  287. self.assertEqual(1, len(glob(os.path.join(self.resultdir, "directdisk-*.direct"))))
  288. def test_compress_gzip(self):
  289. """Test compressing an image with gzip"""
  290. runCmd("wic create wictestdisk "
  291. "--image-name core-image-minimal "
  292. "-c gzip -o %s" % self.resultdir)
  293. self.assertEqual(1, len(glob(os.path.join(self.resultdir, "wictestdisk-*.direct.gz"))))
  294. def test_compress_bzip2(self):
  295. """Test compressing an image with bzip2"""
  296. runCmd("wic create wictestdisk "
  297. "--image-name=core-image-minimal "
  298. "-c bzip2 -o %s" % self.resultdir)
  299. self.assertEqual(1, len(glob(os.path.join(self.resultdir, "wictestdisk-*.direct.bz2"))))
  300. def test_compress_xz(self):
  301. """Test compressing an image with xz"""
  302. runCmd("wic create wictestdisk "
  303. "--image-name=core-image-minimal "
  304. "--compress-with=xz -o %s" % self.resultdir)
  305. self.assertEqual(1, len(glob(os.path.join(self.resultdir, "wictestdisk-*.direct.xz"))))
  306. def test_wrong_compressor(self):
  307. """Test how wic breaks if wrong compressor is provided"""
  308. self.assertEqual(2, runCmd("wic create wictestdisk "
  309. "--image-name=core-image-minimal "
  310. "-c wrong -o %s" % self.resultdir,
  311. ignore_status=True).status)
  312. def test_debug_short(self):
  313. """Test -D option"""
  314. runCmd("wic create wictestdisk "
  315. "--image-name=core-image-minimal "
  316. "-D -o %s" % self.resultdir)
  317. self.assertEqual(1, len(glob(os.path.join(self.resultdir, "wictestdisk-*.direct"))))
  318. self.assertEqual(1, len(glob(os.path.join(self.resultdir, "tmp.wic*"))))
  319. def test_debug_long(self):
  320. """Test --debug option"""
  321. runCmd("wic create wictestdisk "
  322. "--image-name=core-image-minimal "
  323. "--debug -o %s" % self.resultdir)
  324. self.assertEqual(1, len(glob(os.path.join(self.resultdir, "wictestdisk-*.direct"))))
  325. self.assertEqual(1, len(glob(os.path.join(self.resultdir, "tmp.wic*"))))
  326. def test_skip_build_check_short(self):
  327. """Test -s option"""
  328. runCmd("wic create wictestdisk "
  329. "--image-name=core-image-minimal "
  330. "-s -o %s" % self.resultdir)
  331. self.assertEqual(1, len(glob(os.path.join(self.resultdir, "wictestdisk-*.direct"))))
  332. def test_skip_build_check_long(self):
  333. """Test --skip-build-check option"""
  334. runCmd("wic create wictestdisk "
  335. "--image-name=core-image-minimal "
  336. "--skip-build-check "
  337. "--outdir %s" % self.resultdir)
  338. self.assertEqual(1, len(glob(os.path.join(self.resultdir, "wictestdisk-*.direct"))))
  339. def test_build_rootfs_short(self):
  340. """Test -f option"""
  341. runCmd("wic create wictestdisk "
  342. "--image-name=core-image-minimal "
  343. "-f -o %s" % self.resultdir)
  344. self.assertEqual(1, len(glob(os.path.join(self.resultdir, "wictestdisk-*.direct"))))
  345. def test_build_rootfs_long(self):
  346. """Test --build-rootfs option"""
  347. runCmd("wic create wictestdisk "
  348. "--image-name=core-image-minimal "
  349. "--build-rootfs "
  350. "--outdir %s" % self.resultdir)
  351. self.assertEqual(1, len(glob(os.path.join(self.resultdir, "wictestdisk-*.direct"))))
  352. # TODO this doesn't have to be x86-specific
  353. @skipIfNotArch(['i586', 'i686', 'x86_64'])
  354. def test_rootfs_indirect_recipes(self):
  355. """Test usage of rootfs plugin with rootfs recipes"""
  356. runCmd("wic create directdisk-multi-rootfs "
  357. "--image-name=core-image-minimal "
  358. "--rootfs rootfs1=core-image-minimal "
  359. "--rootfs rootfs2=core-image-minimal "
  360. "--outdir %s" % self.resultdir)
  361. self.assertEqual(1, len(glob(os.path.join(self.resultdir, "directdisk-multi-rootfs*.direct"))))
  362. # TODO this doesn't have to be x86-specific
  363. @skipIfNotArch(['i586', 'i686', 'x86_64'])
  364. def test_rootfs_artifacts(self):
  365. """Test usage of rootfs plugin with rootfs paths"""
  366. bb_vars = get_bb_vars(['STAGING_DATADIR', 'RECIPE_SYSROOT_NATIVE'],
  367. 'wic-tools')
  368. bb_vars.update(get_bb_vars(['DEPLOY_DIR_IMAGE', 'IMAGE_ROOTFS'],
  369. 'core-image-minimal'))
  370. bbvars = {key.lower(): value for key, value in bb_vars.items()}
  371. bbvars['wks'] = "directdisk-multi-rootfs"
  372. bbvars['resultdir'] = self.resultdir
  373. runCmd("wic create %(wks)s "
  374. "--bootimg-dir=%(staging_datadir)s "
  375. "--kernel-dir=%(deploy_dir_image)s "
  376. "--native-sysroot=%(recipe_sysroot_native)s "
  377. "--rootfs-dir rootfs1=%(image_rootfs)s "
  378. "--rootfs-dir rootfs2=%(image_rootfs)s "
  379. "--outdir %(resultdir)s" % bbvars)
  380. self.assertEqual(1, len(glob(os.path.join(self.resultdir, "%(wks)s-*.direct" % bbvars))))
  381. def test_exclude_path(self):
  382. """Test --exclude-path wks option."""
  383. oldpath = os.environ['PATH']
  384. os.environ['PATH'] = get_bb_var("PATH", "wic-tools")
  385. try:
  386. wks_file = 'temp.wks'
  387. with open(wks_file, 'w') as wks:
  388. rootfs_dir = get_bb_var('IMAGE_ROOTFS', 'core-image-minimal')
  389. wks.write("""
  390. part / --source rootfs --ondisk mmcblk0 --fstype=ext4 --exclude-path usr
  391. part /usr --source rootfs --ondisk mmcblk0 --fstype=ext4 --rootfs-dir %s/usr
  392. part /etc --source rootfs --ondisk mmcblk0 --fstype=ext4 --exclude-path bin/ --rootfs-dir %s/usr
  393. part /mnt --source rootfs --ondisk mmcblk0 --fstype=ext4 --exclude-path bin/whoami --rootfs-dir %s/usr"""
  394. % (rootfs_dir, rootfs_dir, rootfs_dir))
  395. runCmd("wic create %s -e core-image-minimal -o %s" \
  396. % (wks_file, self.resultdir))
  397. os.remove(wks_file)
  398. wicout = glob(os.path.join(self.resultdir, "%s-*direct" % 'temp'))
  399. self.assertEqual(1, len(wicout))
  400. wicimg = wicout[0]
  401. # verify partition size with wic
  402. res = runCmd("parted -m %s unit b p" % wicimg, stderr=subprocess.PIPE)
  403. # parse parted output which looks like this:
  404. # BYT;\n
  405. # /var/tmp/wic/build/tmpfwvjjkf_-201611101222-hda.direct:200MiB:file:512:512:msdos::;\n
  406. # 1:0.00MiB:200MiB:200MiB:ext4::;\n
  407. partlns = res.output.splitlines()[2:]
  408. self.assertEqual(4, len(partlns))
  409. for part in [1, 2, 3, 4]:
  410. part_file = os.path.join(self.resultdir, "selftest_img.part%d" % part)
  411. partln = partlns[part-1].split(":")
  412. self.assertEqual(7, len(partln))
  413. start = int(partln[1].rstrip("B")) / 512
  414. length = int(partln[3].rstrip("B")) / 512
  415. runCmd("dd if=%s of=%s skip=%d count=%d" %
  416. (wicimg, part_file, start, length))
  417. # Test partition 1, should contain the normal root directories, except
  418. # /usr.
  419. res = runCmd("debugfs -R 'ls -p' %s" % \
  420. os.path.join(self.resultdir, "selftest_img.part1"), stderr=subprocess.PIPE)
  421. files = extract_files(res.output)
  422. self.assertIn("etc", files)
  423. self.assertNotIn("usr", files)
  424. # Partition 2, should contain common directories for /usr, not root
  425. # directories.
  426. res = runCmd("debugfs -R 'ls -p' %s" % \
  427. os.path.join(self.resultdir, "selftest_img.part2"), stderr=subprocess.PIPE)
  428. files = extract_files(res.output)
  429. self.assertNotIn("etc", files)
  430. self.assertNotIn("usr", files)
  431. self.assertIn("share", files)
  432. # Partition 3, should contain the same as partition 2, including the bin
  433. # directory, but not the files inside it.
  434. res = runCmd("debugfs -R 'ls -p' %s" % \
  435. os.path.join(self.resultdir, "selftest_img.part3"), stderr=subprocess.PIPE)
  436. files = extract_files(res.output)
  437. self.assertNotIn("etc", files)
  438. self.assertNotIn("usr", files)
  439. self.assertIn("share", files)
  440. self.assertIn("bin", files)
  441. res = runCmd("debugfs -R 'ls -p bin' %s" % \
  442. os.path.join(self.resultdir, "selftest_img.part3"), stderr=subprocess.PIPE)
  443. files = extract_files(res.output)
  444. self.assertIn(".", files)
  445. self.assertIn("..", files)
  446. self.assertEqual(2, len(files))
  447. # Partition 4, should contain the same as partition 2, including the bin
  448. # directory, but not whoami (a symlink to busybox.nosuid) inside it.
  449. res = runCmd("debugfs -R 'ls -p' %s" % \
  450. os.path.join(self.resultdir, "selftest_img.part4"), stderr=subprocess.PIPE)
  451. files = extract_files(res.output)
  452. self.assertNotIn("etc", files)
  453. self.assertNotIn("usr", files)
  454. self.assertIn("share", files)
  455. self.assertIn("bin", files)
  456. res = runCmd("debugfs -R 'ls -p bin' %s" % \
  457. os.path.join(self.resultdir, "selftest_img.part4"), stderr=subprocess.PIPE)
  458. files = extract_files(res.output)
  459. self.assertIn(".", files)
  460. self.assertIn("..", files)
  461. self.assertIn("who", files)
  462. self.assertNotIn("whoami", files)
  463. for part in [1, 2, 3, 4]:
  464. part_file = os.path.join(self.resultdir, "selftest_img.part%d" % part)
  465. os.remove(part_file)
  466. finally:
  467. os.environ['PATH'] = oldpath
  468. def test_exclude_path_with_extra_space(self):
  469. """Test having --exclude-path with IMAGE_ROOTFS_EXTRA_SPACE. [Yocto #15555]"""
  470. oldpath = os.environ['PATH']
  471. os.environ['PATH'] = get_bb_var("PATH", "wic-tools")
  472. try:
  473. with NamedTemporaryFile("w", suffix=".wks") as wks:
  474. wks.writelines(
  475. ['bootloader --ptable gpt\n',
  476. 'part /boot --size=100M --active --fstype=ext4 --label boot\n',
  477. 'part / --source rootfs --fstype=ext4 --label root --exclude-path boot/\n'])
  478. wks.flush()
  479. config = 'IMAGE_ROOTFS_EXTRA_SPACE = "500000"\n'\
  480. 'DEPENDS:pn-core-image-minimal += "wic-tools"\n'\
  481. 'IMAGE_FSTYPES += "wic"\n'\
  482. 'WKS_FILE = "%s"\n' % wks.name
  483. self.append_config(config)
  484. bitbake('core-image-minimal')
  485. """
  486. the output of "wic ls <image>.wic" will look something like:
  487. Num Start End Size Fstype
  488. 1 17408 136332287 136314880 ext4
  489. 2 136332288 171464703 35132416 ext4
  490. we are looking for the size of partition 2
  491. i.e. in this case the number 35,132,416
  492. without the fix the size will be around 85,403,648
  493. with the fix the size should be around 799,960,064
  494. """
  495. bb_vars = get_bb_vars(['DEPLOY_DIR_IMAGE', 'MACHINE'], 'core-image-minimal')
  496. deploy_dir = bb_vars['DEPLOY_DIR_IMAGE']
  497. machine = bb_vars['MACHINE']
  498. wicout = glob(os.path.join(deploy_dir, "core-image-minimal-%s.rootfs-*.wic" % machine))[0]
  499. size_of_root_partition = int(runCmd("wic ls %s" % wicout).output.split('\n')[2].split()[3])
  500. self.assertGreater(size_of_root_partition, 500000000)
  501. finally:
  502. os.environ['PATH'] = oldpath
  503. def test_include_path(self):
  504. """Test --include-path wks option."""
  505. oldpath = os.environ['PATH']
  506. os.environ['PATH'] = get_bb_var("PATH", "wic-tools")
  507. try:
  508. include_path = os.path.join(self.resultdir, 'test-include')
  509. os.makedirs(include_path)
  510. with open(os.path.join(include_path, 'test-file'), 'w') as t:
  511. t.write("test\n")
  512. wks_file = os.path.join(include_path, 'temp.wks')
  513. with open(wks_file, 'w') as wks:
  514. rootfs_dir = get_bb_var('IMAGE_ROOTFS', 'core-image-minimal')
  515. wks.write("""
  516. part /part1 --source rootfs --ondisk mmcblk0 --fstype=ext4
  517. part /part2 --source rootfs --ondisk mmcblk0 --fstype=ext4 --include-path %s"""
  518. % (include_path))
  519. runCmd("wic create %s -e core-image-minimal -o %s" \
  520. % (wks_file, self.resultdir))
  521. part1 = glob(os.path.join(self.resultdir, 'temp-*.direct.p1'))[0]
  522. part2 = glob(os.path.join(self.resultdir, 'temp-*.direct.p2'))[0]
  523. # Test partition 1, should not contain 'test-file'
  524. res = runCmd("debugfs -R 'ls -p' %s" % (part1), stderr=subprocess.PIPE)
  525. files = extract_files(res.output)
  526. self.assertNotIn('test-file', files)
  527. self.assertEqual(True, files_own_by_root(res.output))
  528. # Test partition 2, should contain 'test-file'
  529. res = runCmd("debugfs -R 'ls -p' %s" % (part2), stderr=subprocess.PIPE)
  530. files = extract_files(res.output)
  531. self.assertIn('test-file', files)
  532. self.assertEqual(True, files_own_by_root(res.output))
  533. finally:
  534. os.environ['PATH'] = oldpath
  535. def test_include_path_embeded(self):
  536. """Test --include-path wks option."""
  537. oldpath = os.environ['PATH']
  538. os.environ['PATH'] = get_bb_var("PATH", "wic-tools")
  539. try:
  540. include_path = os.path.join(self.resultdir, 'test-include')
  541. os.makedirs(include_path)
  542. with open(os.path.join(include_path, 'test-file'), 'w') as t:
  543. t.write("test\n")
  544. wks_file = os.path.join(include_path, 'temp.wks')
  545. with open(wks_file, 'w') as wks:
  546. wks.write("""
  547. part / --source rootfs --fstype=ext4 --include-path %s --include-path core-image-minimal-mtdutils export/"""
  548. % (include_path))
  549. runCmd("wic create %s -e core-image-minimal -o %s" \
  550. % (wks_file, self.resultdir))
  551. part1 = glob(os.path.join(self.resultdir, 'temp-*.direct.p1'))[0]
  552. res = runCmd("debugfs -R 'ls -p' %s" % (part1), stderr=subprocess.PIPE)
  553. files = extract_files(res.output)
  554. self.assertIn('test-file', files)
  555. self.assertEqual(True, files_own_by_root(res.output))
  556. res = runCmd("debugfs -R 'ls -p /export/etc/' %s" % (part1), stderr=subprocess.PIPE)
  557. files = extract_files(res.output)
  558. self.assertIn('passwd', files)
  559. self.assertEqual(True, files_own_by_root(res.output))
  560. finally:
  561. os.environ['PATH'] = oldpath
  562. def test_include_path_errors(self):
  563. """Test --include-path wks option error handling."""
  564. wks_file = 'temp.wks'
  565. # Absolute argument.
  566. with open(wks_file, 'w') as wks:
  567. wks.write("part / --source rootfs --fstype=ext4 --include-path core-image-minimal-mtdutils /export")
  568. self.assertNotEqual(0, runCmd("wic create %s -e core-image-minimal -o %s" \
  569. % (wks_file, self.resultdir), ignore_status=True).status)
  570. os.remove(wks_file)
  571. # Argument pointing to parent directory.
  572. with open(wks_file, 'w') as wks:
  573. wks.write("part / --source rootfs --fstype=ext4 --include-path core-image-minimal-mtdutils ././..")
  574. self.assertNotEqual(0, runCmd("wic create %s -e core-image-minimal -o %s" \
  575. % (wks_file, self.resultdir), ignore_status=True).status)
  576. os.remove(wks_file)
  577. # 3 Argument pointing to parent directory.
  578. with open(wks_file, 'w') as wks:
  579. wks.write("part / --source rootfs --fstype=ext4 --include-path core-image-minimal-mtdutils export/ dummy")
  580. self.assertNotEqual(0, runCmd("wic create %s -e core-image-minimal -o %s" \
  581. % (wks_file, self.resultdir), ignore_status=True).status)
  582. os.remove(wks_file)
  583. def test_exclude_path_errors(self):
  584. """Test --exclude-path wks option error handling."""
  585. wks_file = 'temp.wks'
  586. # Absolute argument.
  587. with open(wks_file, 'w') as wks:
  588. wks.write("part / --source rootfs --ondisk mmcblk0 --fstype=ext4 --exclude-path /usr")
  589. self.assertNotEqual(0, runCmd("wic create %s -e core-image-minimal -o %s" \
  590. % (wks_file, self.resultdir), ignore_status=True).status)
  591. os.remove(wks_file)
  592. # Argument pointing to parent directory.
  593. with open(wks_file, 'w') as wks:
  594. wks.write("part / --source rootfs --ondisk mmcblk0 --fstype=ext4 --exclude-path ././..")
  595. self.assertNotEqual(0, runCmd("wic create %s -e core-image-minimal -o %s" \
  596. % (wks_file, self.resultdir), ignore_status=True).status)
  597. os.remove(wks_file)
  598. def test_permissions(self):
  599. """Test permissions are respected"""
  600. # prepare wicenv and rootfs
  601. bitbake('core-image-minimal core-image-minimal-mtdutils -c do_rootfs_wicenv')
  602. oldpath = os.environ['PATH']
  603. os.environ['PATH'] = get_bb_var("PATH", "wic-tools")
  604. t_normal = """
  605. part / --source rootfs --fstype=ext4
  606. """
  607. t_exclude = """
  608. part / --source rootfs --fstype=ext4 --exclude-path=home
  609. """
  610. t_multi = """
  611. part / --source rootfs --ondisk sda --fstype=ext4
  612. part /export --source rootfs --rootfs=core-image-minimal-mtdutils --fstype=ext4
  613. """
  614. t_change = """
  615. part / --source rootfs --ondisk sda --fstype=ext4 --exclude-path=etc/   
  616. part /etc --source rootfs --fstype=ext4 --change-directory=etc
  617. """
  618. tests = [t_normal, t_exclude, t_multi, t_change]
  619. try:
  620. for test in tests:
  621. include_path = os.path.join(self.resultdir, 'test-include')
  622. os.makedirs(include_path)
  623. wks_file = os.path.join(include_path, 'temp.wks')
  624. with open(wks_file, 'w') as wks:
  625. wks.write(test)
  626. runCmd("wic create %s -e core-image-minimal -o %s" \
  627. % (wks_file, self.resultdir))
  628. for part in glob(os.path.join(self.resultdir, 'temp-*.direct.p*')):
  629. res = runCmd("debugfs -R 'ls -p' %s" % (part), stderr=subprocess.PIPE)
  630. self.assertEqual(True, files_own_by_root(res.output))
  631. config = 'IMAGE_FSTYPES += "wic"\nWKS_FILE = "%s"\n' % wks_file
  632. self.append_config(config)
  633. bitbake('core-image-minimal')
  634. tmpdir = os.path.join(get_bb_var('WORKDIR', 'core-image-minimal'),'build-wic')
  635. # check each partition for permission
  636. for part in glob(os.path.join(tmpdir, 'temp-*.direct.p*')):
  637. res = runCmd("debugfs -R 'ls -p' %s" % (part), stderr=subprocess.PIPE)
  638. self.assertTrue(files_own_by_root(res.output)
  639. ,msg='Files permission incorrect using wks set "%s"' % test)
  640. # clean config and result directory for next cases
  641. self.remove_config(config)
  642. rmtree(self.resultdir, ignore_errors=True)
  643. finally:
  644. os.environ['PATH'] = oldpath
  645. def test_change_directory(self):
  646. """Test --change-directory wks option."""
  647. oldpath = os.environ['PATH']
  648. os.environ['PATH'] = get_bb_var("PATH", "wic-tools")
  649. try:
  650. include_path = os.path.join(self.resultdir, 'test-include')
  651. os.makedirs(include_path)
  652. wks_file = os.path.join(include_path, 'temp.wks')
  653. with open(wks_file, 'w') as wks:
  654. wks.write("part /etc --source rootfs --fstype=ext4 --change-directory=etc")
  655. runCmd("wic create %s -e core-image-minimal -o %s" \
  656. % (wks_file, self.resultdir))
  657. part1 = glob(os.path.join(self.resultdir, 'temp-*.direct.p1'))[0]
  658. res = runCmd("debugfs -R 'ls -p' %s" % (part1), stderr=subprocess.PIPE)
  659. files = extract_files(res.output)
  660. self.assertIn('passwd', files)
  661. finally:
  662. os.environ['PATH'] = oldpath
  663. def test_change_directory_errors(self):
  664. """Test --change-directory wks option error handling."""
  665. wks_file = 'temp.wks'
  666. # Absolute argument.
  667. with open(wks_file, 'w') as wks:
  668. wks.write("part / --source rootfs --fstype=ext4 --change-directory /usr")
  669. self.assertNotEqual(0, runCmd("wic create %s -e core-image-minimal -o %s" \
  670. % (wks_file, self.resultdir), ignore_status=True).status)
  671. os.remove(wks_file)
  672. # Argument pointing to parent directory.
  673. with open(wks_file, 'w') as wks:
  674. wks.write("part / --source rootfs --fstype=ext4 --change-directory ././..")
  675. self.assertNotEqual(0, runCmd("wic create %s -e core-image-minimal -o %s" \
  676. % (wks_file, self.resultdir), ignore_status=True).status)
  677. os.remove(wks_file)
  678. def test_no_fstab_update(self):
  679. """Test --no-fstab-update wks option."""
  680. oldpath = os.environ['PATH']
  681. os.environ['PATH'] = get_bb_var("PATH", "wic-tools")
  682. # Get stock fstab from base-files recipe
  683. bitbake('base-files -c do_install')
  684. bf_fstab = os.path.join(get_bb_var('D', 'base-files'), 'etc', 'fstab')
  685. self.assertEqual(True, os.path.exists(bf_fstab))
  686. bf_fstab_md5sum = runCmd('md5sum %s ' % bf_fstab).output.split(" ")[0]
  687. try:
  688. no_fstab_update_path = os.path.join(self.resultdir, 'test-no-fstab-update')
  689. os.makedirs(no_fstab_update_path)
  690. wks_file = os.path.join(no_fstab_update_path, 'temp.wks')
  691. with open(wks_file, 'w') as wks:
  692. wks.writelines(['part / --source rootfs --fstype=ext4 --label rootfs\n',
  693. 'part /mnt/p2 --source rootfs --rootfs-dir=core-image-minimal ',
  694. '--fstype=ext4 --label p2 --no-fstab-update\n'])
  695. runCmd("wic create %s -e core-image-minimal -o %s" \
  696. % (wks_file, self.resultdir))
  697. part_fstab_md5sum = []
  698. for i in range(1, 3):
  699. part = glob(os.path.join(self.resultdir, 'temp-*.direct.p') + str(i))[0]
  700. part_fstab = runCmd("debugfs -R 'cat etc/fstab' %s" % (part), stderr=subprocess.PIPE)
  701. part_fstab_md5sum.append(hashlib.md5((part_fstab.output + "\n\n").encode('utf-8')).hexdigest())
  702. # '/etc/fstab' in partition 2 should contain the same stock fstab file
  703. # as the one installed by the base-file recipe.
  704. self.assertEqual(bf_fstab_md5sum, part_fstab_md5sum[1])
  705. # '/etc/fstab' in partition 1 should contain an updated fstab file.
  706. self.assertNotEqual(bf_fstab_md5sum, part_fstab_md5sum[0])
  707. finally:
  708. os.environ['PATH'] = oldpath
  709. def test_no_fstab_update_errors(self):
  710. """Test --no-fstab-update wks option error handling."""
  711. wks_file = 'temp.wks'
  712. # Absolute argument.
  713. with open(wks_file, 'w') as wks:
  714. wks.write("part / --source rootfs --fstype=ext4 --no-fstab-update /etc")
  715. self.assertNotEqual(0, runCmd("wic create %s -e core-image-minimal -o %s" \
  716. % (wks_file, self.resultdir), ignore_status=True).status)
  717. os.remove(wks_file)
  718. # Argument pointing to parent directory.
  719. with open(wks_file, 'w') as wks:
  720. wks.write("part / --source rootfs --fstype=ext4 --no-fstab-update ././..")
  721. self.assertNotEqual(0, runCmd("wic create %s -e core-image-minimal -o %s" \
  722. % (wks_file, self.resultdir), ignore_status=True).status)
  723. os.remove(wks_file)
  724. def test_extra_space(self):
  725. """Test --extra-space wks option."""
  726. extraspace = 1024**3
  727. runCmd("wic create wictestdisk "
  728. "--image-name core-image-minimal "
  729. "--extra-space %i -o %s" % (extraspace ,self.resultdir))
  730. wicout = glob(os.path.join(self.resultdir, "wictestdisk-*.direct"))
  731. self.assertEqual(1, len(wicout))
  732. size = os.path.getsize(wicout[0])
  733. self.assertTrue(size > extraspace, msg="Extra space not present (%s vs %s)" % (size, extraspace))
  734. def test_no_table(self):
  735. """Test --no-table wks option."""
  736. wks_file = 'temp.wks'
  737. # Absolute argument.
  738. with open(wks_file, 'w') as wks:
  739. wks.write("part testspace --no-table --fixed-size 16k --offset 4080k")
  740. runCmd("wic create %s --image-name core-image-minimal -o %s" % (wks_file, self.resultdir))
  741. wicout = glob(os.path.join(self.resultdir, "*.*"))
  742. self.assertEqual(1, len(wicout))
  743. size = os.path.getsize(wicout[0])
  744. self.assertEqual(size, 4 * 1024 * 1024)
  745. os.remove(wks_file)
  746. def test_partition_hidden_attributes(self):
  747. """Test --hidden wks option."""
  748. wks_file = 'temp.wks'
  749. sysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'wic-tools')
  750. try:
  751. with open(wks_file, 'w') as wks:
  752. wks.write("""
  753. part / --source rootfs --fstype=ext4
  754. part / --source rootfs --fstype=ext4 --hidden
  755. bootloader --ptable gpt""")
  756. runCmd("wic create %s -e core-image-minimal -o %s" \
  757. % (wks_file, self.resultdir))
  758. wicout = os.path.join(self.resultdir, "*.direct")
  759. result = runCmd("%s/usr/sbin/sfdisk --part-attrs %s 1" % (sysroot, wicout))
  760. self.assertEqual('', result.output)
  761. result = runCmd("%s/usr/sbin/sfdisk --part-attrs %s 2" % (sysroot, wicout))
  762. self.assertEqual('RequiredPartition', result.output)
  763. finally:
  764. os.remove(wks_file)
  765. def test_wic_sector_size(self):
  766. """Test generation image sector size"""
  767. oldpath = os.environ['PATH']
  768. os.environ['PATH'] = get_bb_var("PATH", "wic-tools")
  769. try:
  770. # Add WIC_SECTOR_SIZE into config
  771. config = 'WIC_SECTOR_SIZE = "4096"\n'\
  772. 'WICVARS:append = " WIC_SECTOR_SIZE"\n'
  773. self.append_config(config)
  774. bitbake('core-image-minimal')
  775. # Check WIC_SECTOR_SIZE apply to bitbake variable
  776. wic_sector_size_str = get_bb_var('WIC_SECTOR_SIZE', 'core-image-minimal')
  777. wic_sector_size = int(wic_sector_size_str)
  778. self.assertEqual(4096, wic_sector_size)
  779. self.logger.info("Test wic_sector_size: %d \n" % wic_sector_size)
  780. with NamedTemporaryFile("w", suffix=".wks") as wks:
  781. wks.writelines(
  782. ['bootloader --ptable gpt\n',
  783. 'part --fstype ext4 --source rootfs --label rofs-a --mkfs-extraopts "-b 4096"\n',
  784. 'part --fstype ext4 --source rootfs --use-uuid --mkfs-extraopts "-b 4096"\n'])
  785. wks.flush()
  786. cmd = "wic create %s -e core-image-minimal -o %s" % (wks.name, self.resultdir)
  787. runCmd(cmd)
  788. wksname = os.path.splitext(os.path.basename(wks.name))[0]
  789. images = glob(os.path.join(self.resultdir, "%s-*direct" % wksname))
  790. self.assertEqual(1, len(images))
  791. sysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'wic-tools')
  792. # list partitions
  793. result = runCmd("wic ls %s -n %s" % (images[0], sysroot))
  794. self.assertEqual(3, len(result.output.split('\n')))
  795. # verify partition size with wic
  796. res = runCmd("export PARTED_SECTOR_SIZE=%d; parted -m %s unit b p" % (wic_sector_size, images[0]),
  797. stderr=subprocess.PIPE)
  798. # parse parted output which looks like this:
  799. # BYT;\n
  800. # /var/tmp/wic/build/tmpgjzzefdd-202410281021-sda.direct:78569472B:file:4096:4096:gpt::;\n
  801. # 1:139264B:39284735B:39145472B:ext4:rofs-a:;\n
  802. # 2:39284736B:78430207B:39145472B:ext4:primary:;\n
  803. disk_info = res.output.splitlines()[1]
  804. # Check sector sizes
  805. sector_size_logical = int(disk_info.split(":")[3])
  806. sector_size_physical = int(disk_info.split(":")[4])
  807. self.assertEqual(wic_sector_size, sector_size_logical, "Logical sector size is not %d." % wic_sector_size)
  808. self.assertEqual(wic_sector_size, sector_size_physical, "Physical sector size is not %d." % wic_sector_size)
  809. finally:
  810. os.environ['PATH'] = oldpath
  811. class Wic2(WicTestCase):
  812. def test_bmap_short(self):
  813. """Test generation of .bmap file -m option"""
  814. cmd = "wic create wictestdisk -e core-image-minimal -m -o %s" % self.resultdir
  815. runCmd(cmd)
  816. self.assertEqual(1, len(glob(os.path.join(self.resultdir, "wictestdisk-*direct"))))
  817. self.assertEqual(1, len(glob(os.path.join(self.resultdir, "wictestdisk-*direct.bmap"))))
  818. def test_bmap_long(self):
  819. """Test generation of .bmap file --bmap option"""
  820. cmd = "wic create wictestdisk -e core-image-minimal --bmap -o %s" % self.resultdir
  821. runCmd(cmd)
  822. self.assertEqual(1, len(glob(os.path.join(self.resultdir, "wictestdisk-*direct"))))
  823. self.assertEqual(1, len(glob(os.path.join(self.resultdir, "wictestdisk-*direct.bmap"))))
  824. def test_image_env(self):
  825. """Test generation of <image>.env files."""
  826. image = 'core-image-minimal'
  827. imgdatadir = self._get_image_env_path(image)
  828. bb_vars = get_bb_vars(['IMAGE_BASENAME', 'WICVARS'], image)
  829. basename = bb_vars['IMAGE_BASENAME']
  830. self.assertEqual(basename, image)
  831. path = os.path.join(imgdatadir, basename) + '.env'
  832. self.assertTrue(os.path.isfile(path), msg="File %s wasn't generated as expected" % path)
  833. wicvars = set(bb_vars['WICVARS'].split())
  834. # filter out optional variables
  835. wicvars = wicvars.difference(('DEPLOY_DIR_IMAGE', 'IMAGE_BOOT_FILES',
  836. 'INITRD', 'INITRD_LIVE', 'ISODIR','INITRAMFS_IMAGE',
  837. 'INITRAMFS_IMAGE_BUNDLE', 'INITRAMFS_LINK_NAME',
  838. 'APPEND', 'IMAGE_EFI_BOOT_FILES'))
  839. with open(path) as envfile:
  840. content = dict(line.split("=", 1) for line in envfile)
  841. # test if variables used by wic present in the .env file
  842. for var in wicvars:
  843. self.assertTrue(var in content, "%s is not in .env file" % var)
  844. self.assertTrue(content[var], "%s doesn't have a value (%s)" % (var, content[var]))
  845. def test_image_vars_dir_short(self):
  846. """Test image vars directory selection -v option"""
  847. image = 'core-image-minimal'
  848. imgenvdir = self._get_image_env_path(image)
  849. native_sysroot = get_bb_var("RECIPE_SYSROOT_NATIVE", "wic-tools")
  850. runCmd("wic create wictestdisk "
  851. "--image-name=%s -v %s -n %s -o %s"
  852. % (image, imgenvdir, native_sysroot,
  853. self.resultdir))
  854. self.assertEqual(1, len(glob(os.path.join(self.resultdir, "wictestdisk-*direct"))))
  855. def test_image_vars_dir_long(self):
  856. """Test image vars directory selection --vars option"""
  857. image = 'core-image-minimal'
  858. imgenvdir = self._get_image_env_path(image)
  859. native_sysroot = get_bb_var("RECIPE_SYSROOT_NATIVE", "wic-tools")
  860. runCmd("wic create wictestdisk "
  861. "--image-name=%s "
  862. "--vars %s "
  863. "--native-sysroot %s "
  864. "--outdir %s"
  865. % (image, imgenvdir, native_sysroot,
  866. self.resultdir))
  867. self.assertEqual(1, len(glob(os.path.join(self.resultdir, "wictestdisk-*direct"))))
  868. # TODO this test could also work on aarch64
  869. @skipIfNotArch(['i586', 'i686', 'x86_64'])
  870. def test_wic_image_type(self):
  871. """Test building wic images by bitbake"""
  872. config = 'IMAGE_FSTYPES += "wic"\nWKS_FILE = "wic-image-minimal"\n'\
  873. 'MACHINE_FEATURES:append = " efi"\n'
  874. self.append_config(config)
  875. image = 'wic-image-minimal'
  876. bitbake(image)
  877. self.remove_config(config)
  878. bb_vars = get_bb_vars(['DEPLOY_DIR_IMAGE', 'IMAGE_LINK_NAME'], image)
  879. prefix = os.path.join(bb_vars['DEPLOY_DIR_IMAGE'], '%s.' % bb_vars['IMAGE_LINK_NAME'])
  880. # check if we have result image and manifests symlinks
  881. # pointing to existing files
  882. for suffix in ('wic', 'manifest'):
  883. path = prefix + suffix
  884. self.assertTrue(os.path.islink(path), msg="Link %s wasn't generated as expected" % path)
  885. self.assertTrue(os.path.isfile(os.path.realpath(path)), msg="File linked to by %s wasn't generated as expected" % path)
  886. # TODO this should work on aarch64
  887. @skipIfNotArch(['i586', 'i686', 'x86_64'])
  888. @OETestTag("runqemu")
  889. def test_qemu(self):
  890. """Test wic-image-minimal under qemu"""
  891. config = 'IMAGE_FSTYPES += "wic"\nWKS_FILE = "wic-image-minimal"\n'\
  892. 'MACHINE_FEATURES:append = " efi"\n'
  893. self.append_config(config)
  894. bitbake('wic-image-minimal')
  895. self.remove_config(config)
  896. runqemu_params = get_bb_var('TEST_RUNQEMUPARAMS', 'wic-image-minimal') or ""
  897. with runqemu('wic-image-minimal', ssh=False, runqemuparams='%s nographic' % (runqemu_params)) as qemu:
  898. cmd = "mount | grep '^/dev/' | cut -f1,3 -d ' ' | egrep -c -e '/dev/sda1 /boot' " \
  899. "-e '/dev/root /|/dev/sda2 /' -e '/dev/sda3 /media' -e '/dev/sda4 /mnt'"
  900. status, output = qemu.run_serial(cmd)
  901. self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output))
  902. self.assertEqual(output, '4')
  903. cmd = "grep UUID=2c71ef06-a81d-4735-9d3a-379b69c6bdba /etc/fstab"
  904. status, output = qemu.run_serial(cmd)
  905. self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output))
  906. self.assertEqual(output, 'UUID=2c71ef06-a81d-4735-9d3a-379b69c6bdba\t/media\text4\tdefaults\t0\t0')
  907. @skipIfNotArch(['i586', 'i686', 'x86_64'])
  908. @OETestTag("runqemu")
  909. def test_qemu_efi(self):
  910. """Test core-image-minimal efi image under qemu"""
  911. config = 'IMAGE_FSTYPES = "wic"\nWKS_FILE = "mkefidisk.wks"\n'
  912. self.append_config(config)
  913. bitbake('core-image-minimal ovmf')
  914. self.remove_config(config)
  915. runqemu_params = get_bb_var('TEST_RUNQEMUPARAMS', 'core-image-minimal') or ""
  916. with runqemu('core-image-minimal', ssh=False,
  917. runqemuparams='%s nographic ovmf' % (runqemu_params), image_fstype='wic') as qemu:
  918. cmd = "grep sda. /proc/partitions |wc -l"
  919. status, output = qemu.run_serial(cmd)
  920. self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output))
  921. self.assertEqual(output, '3')
  922. @staticmethod
  923. def _make_fixed_size_wks(size):
  924. """
  925. Create a wks of an image with a single partition. Size of the partition is set
  926. using --fixed-size flag. Returns a tuple: (path to wks file, wks image name)
  927. """
  928. with NamedTemporaryFile("w", suffix=".wks", delete=False) as tempf:
  929. wkspath = tempf.name
  930. tempf.write("part " \
  931. "--source rootfs --ondisk hda --align 4 --fixed-size %d "
  932. "--fstype=ext4\n" % size)
  933. return wkspath
  934. def _get_wic_partitions(self, wkspath, native_sysroot=None, ignore_status=False):
  935. p = runCmd("wic create %s -e core-image-minimal -o %s" % (wkspath, self.resultdir),
  936. ignore_status=ignore_status)
  937. if p.status:
  938. return (p, None)
  939. wksname = os.path.splitext(os.path.basename(wkspath))[0]
  940. wicout = glob(os.path.join(self.resultdir, "%s-*direct" % wksname))
  941. if not wicout:
  942. return (p, None)
  943. wicimg = wicout[0]
  944. if not native_sysroot:
  945. native_sysroot = get_bb_var("RECIPE_SYSROOT_NATIVE", "wic-tools")
  946. # verify partition size with wic
  947. res = runCmd("parted -m %s unit kib p" % wicimg,
  948. native_sysroot=native_sysroot, stderr=subprocess.PIPE)
  949. # parse parted output which looks like this:
  950. # BYT;\n
  951. # /var/tmp/wic/build/tmpfwvjjkf_-201611101222-hda.direct:200MiB:file:512:512:msdos::;\n
  952. # 1:0.00MiB:200MiB:200MiB:ext4::;\n
  953. return (p, res.output.splitlines()[2:])
  954. def test_fixed_size(self):
  955. """
  956. Test creation of a simple image with partition size controlled through
  957. --fixed-size flag
  958. """
  959. wkspath = Wic2._make_fixed_size_wks(200)
  960. _, partlns = self._get_wic_partitions(wkspath)
  961. os.remove(wkspath)
  962. self.assertEqual(partlns, [
  963. "1:4.00kiB:204804kiB:204800kiB:ext4::;",
  964. ])
  965. def test_fixed_size_error(self):
  966. """
  967. Test creation of a simple image with partition size controlled through
  968. --fixed-size flag. The size of partition is intentionally set to 1MiB
  969. in order to trigger an error in wic.
  970. """
  971. wkspath = Wic2._make_fixed_size_wks(1)
  972. p, _ = self._get_wic_partitions(wkspath, ignore_status=True)
  973. os.remove(wkspath)
  974. self.assertNotEqual(p.status, 0, "wic exited successfully when an error was expected:\n%s" % p.output)
  975. def test_offset(self):
  976. native_sysroot = get_bb_var("RECIPE_SYSROOT_NATIVE", "wic-tools")
  977. with NamedTemporaryFile("w", suffix=".wks") as tempf:
  978. # Test that partitions are placed at the correct offsets, default KB
  979. tempf.write("bootloader --ptable gpt\n" \
  980. "part / --source rootfs --ondisk hda --offset 32 --fixed-size 100M --fstype=ext4\n" \
  981. "part /bar --ondisk hda --offset 102432 --fixed-size 100M --fstype=ext4\n")
  982. tempf.flush()
  983. _, partlns = self._get_wic_partitions(tempf.name, native_sysroot)
  984. self.assertEqual(partlns, [
  985. "1:32.0kiB:102432kiB:102400kiB:ext4:primary:;",
  986. "2:102432kiB:204832kiB:102400kiB:ext4:primary:;",
  987. ])
  988. with NamedTemporaryFile("w", suffix=".wks") as tempf:
  989. # Test that partitions are placed at the correct offsets, same with explicit KB
  990. tempf.write("bootloader --ptable gpt\n" \
  991. "part / --source rootfs --ondisk hda --offset 32K --fixed-size 100M --fstype=ext4\n" \
  992. "part /bar --ondisk hda --offset 102432K --fixed-size 100M --fstype=ext4\n")
  993. tempf.flush()
  994. _, partlns = self._get_wic_partitions(tempf.name, native_sysroot)
  995. self.assertEqual(partlns, [
  996. "1:32.0kiB:102432kiB:102400kiB:ext4:primary:;",
  997. "2:102432kiB:204832kiB:102400kiB:ext4:primary:;",
  998. ])
  999. with NamedTemporaryFile("w", suffix=".wks") as tempf:
  1000. # Test that partitions are placed at the correct offsets using MB
  1001. tempf.write("bootloader --ptable gpt\n" \
  1002. "part / --source rootfs --ondisk hda --offset 32K --fixed-size 100M --fstype=ext4\n" \
  1003. "part /bar --ondisk hda --offset 101M --fixed-size 100M --fstype=ext4\n")
  1004. tempf.flush()
  1005. _, partlns = self._get_wic_partitions(tempf.name, native_sysroot)
  1006. self.assertEqual(partlns, [
  1007. "1:32.0kiB:102432kiB:102400kiB:ext4:primary:;",
  1008. "2:103424kiB:205824kiB:102400kiB:ext4:primary:;",
  1009. ])
  1010. with NamedTemporaryFile("w", suffix=".wks") as tempf:
  1011. # Test that partitions can be placed on a 512 byte sector boundary
  1012. tempf.write("bootloader --ptable gpt\n" \
  1013. "part / --source rootfs --ondisk hda --offset 65s --fixed-size 99M --fstype=ext4\n" \
  1014. "part /bar --ondisk hda --offset 102432 --fixed-size 100M --fstype=ext4\n")
  1015. tempf.flush()
  1016. _, partlns = self._get_wic_partitions(tempf.name, native_sysroot)
  1017. self.assertEqual(partlns, [
  1018. "1:32.5kiB:101408kiB:101376kiB:ext4:primary:;",
  1019. "2:102432kiB:204832kiB:102400kiB:ext4:primary:;",
  1020. ])
  1021. with NamedTemporaryFile("w", suffix=".wks") as tempf:
  1022. # Test that a partition can be placed immediately after a MSDOS partition table
  1023. tempf.write("bootloader --ptable msdos\n" \
  1024. "part / --source rootfs --ondisk hda --offset 1s --fixed-size 100M --fstype=ext4\n")
  1025. tempf.flush()
  1026. _, partlns = self._get_wic_partitions(tempf.name, native_sysroot)
  1027. self.assertEqual(partlns, [
  1028. "1:0.50kiB:102400kiB:102400kiB:ext4::;",
  1029. ])
  1030. with NamedTemporaryFile("w", suffix=".wks") as tempf:
  1031. # Test that image creation fails if the partitions would overlap
  1032. tempf.write("bootloader --ptable gpt\n" \
  1033. "part / --source rootfs --ondisk hda --offset 32 --fixed-size 100M --fstype=ext4\n" \
  1034. "part /bar --ondisk hda --offset 102431 --fixed-size 100M --fstype=ext4\n")
  1035. tempf.flush()
  1036. p, _ = self._get_wic_partitions(tempf.name, ignore_status=True)
  1037. self.assertNotEqual(p.status, 0, "wic exited successfully when an error was expected:\n%s" % p.output)
  1038. with NamedTemporaryFile("w", suffix=".wks") as tempf:
  1039. # Test that partitions are not allowed to overlap with the booloader
  1040. tempf.write("bootloader --ptable gpt\n" \
  1041. "part / --source rootfs --ondisk hda --offset 8 --fixed-size 100M --fstype=ext4\n")
  1042. tempf.flush()
  1043. p, _ = self._get_wic_partitions(tempf.name, ignore_status=True)
  1044. self.assertNotEqual(p.status, 0, "wic exited successfully when an error was expected:\n%s" % p.output)
  1045. def test_extra_space(self):
  1046. native_sysroot = get_bb_var("RECIPE_SYSROOT_NATIVE", "wic-tools")
  1047. with NamedTemporaryFile("w", suffix=".wks") as tempf:
  1048. tempf.write("bootloader --ptable gpt\n" \
  1049. "part / --source rootfs --ondisk hda --extra-space 200M --fstype=ext4\n")
  1050. tempf.flush()
  1051. _, partlns = self._get_wic_partitions(tempf.name, native_sysroot)
  1052. self.assertEqual(len(partlns), 1)
  1053. size = partlns[0].split(':')[3]
  1054. self.assertRegex(size, r'^[0-9]+kiB$')
  1055. size = int(size[:-3])
  1056. self.assertGreaterEqual(size, 204800)
  1057. # TODO this test could also work on aarch64
  1058. @skipIfNotArch(['i586', 'i686', 'x86_64'])
  1059. @OETestTag("runqemu")
  1060. def test_rawcopy_plugin_qemu(self):
  1061. """Test rawcopy plugin in qemu"""
  1062. # build ext4 and then use it for a wic image
  1063. config = 'IMAGE_FSTYPES = "ext4"\n'
  1064. self.append_config(config)
  1065. bitbake('core-image-minimal')
  1066. image_link_name = get_bb_var('IMAGE_LINK_NAME', 'core-image-minimal')
  1067. self.remove_config(config)
  1068. config = 'IMAGE_FSTYPES = "wic"\n' \
  1069. 'IMAGE_LINK_NAME_CORE_IMAGE_MINIMAL = "%s"\n'\
  1070. 'WKS_FILE = "test_rawcopy_plugin.wks.in"\n'\
  1071. % image_link_name
  1072. self.append_config(config)
  1073. bitbake('core-image-minimal-mtdutils')
  1074. self.remove_config(config)
  1075. runqemu_params = get_bb_var('TEST_RUNQEMUPARAMS', 'core-image-minimal-mtdutils') or ""
  1076. with runqemu('core-image-minimal-mtdutils', ssh=False,
  1077. runqemuparams='%s nographic' % (runqemu_params), image_fstype='wic') as qemu:
  1078. cmd = "grep sda. /proc/partitions |wc -l"
  1079. status, output = qemu.run_serial(cmd)
  1080. self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output))
  1081. self.assertEqual(output, '2')
  1082. def _rawcopy_plugin(self, fstype):
  1083. """Test rawcopy plugin"""
  1084. image = 'core-image-minimal'
  1085. bb_vars = get_bb_vars(['DEPLOY_DIR_IMAGE', 'IMAGE_LINK_NAME'], image)
  1086. params = ',unpack' if fstype.endswith('.gz') else ''
  1087. with NamedTemporaryFile("w", suffix=".wks") as wks:
  1088. wks.write('part / --source rawcopy --sourceparams="file=%s.%s%s"\n'\
  1089. % (bb_vars['IMAGE_LINK_NAME'], fstype, params))
  1090. wks.flush()
  1091. cmd = "wic create %s -e %s -o %s" % (wks.name, image, self.resultdir)
  1092. runCmd(cmd)
  1093. wksname = os.path.splitext(os.path.basename(wks.name))[0]
  1094. out = glob(os.path.join(self.resultdir, "%s-*direct" % wksname))
  1095. self.assertEqual(1, len(out))
  1096. def test_rawcopy_plugin(self):
  1097. config = 'IMAGE_FSTYPES = "ext4"\n'
  1098. self.append_config(config)
  1099. self.assertEqual(0, bitbake('core-image-minimal').status)
  1100. self.remove_config(config)
  1101. self._rawcopy_plugin('ext4')
  1102. def test_rawcopy_plugin_unpack(self):
  1103. fstype = 'ext4.gz'
  1104. config = 'IMAGE_FSTYPES = "%s"\n' % fstype
  1105. self.append_config(config)
  1106. self.assertEqual(0, bitbake('core-image-minimal').status)
  1107. self.remove_config(config)
  1108. self._rawcopy_plugin(fstype)
  1109. def test_empty_plugin(self):
  1110. """Test empty plugin"""
  1111. config = 'IMAGE_FSTYPES = "wic"\nWKS_FILE = "test_empty_plugin.wks"\n'
  1112. self.append_config(config)
  1113. image = 'core-image-minimal'
  1114. bitbake(image)
  1115. self.remove_config(config)
  1116. bb_vars = get_bb_vars(['DEPLOY_DIR_IMAGE', 'IMAGE_LINK_NAME'], image)
  1117. image_path = os.path.join(bb_vars['DEPLOY_DIR_IMAGE'], '%s.wic' % bb_vars['IMAGE_LINK_NAME'])
  1118. self.assertTrue(os.path.exists(image_path), msg="Image file %s wasn't generated as expected" % image_path)
  1119. sysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'wic-tools')
  1120. # Fstype column from 'wic ls' should be empty for the second partition
  1121. # as listed in test_empty_plugin.wks
  1122. result = runCmd("wic ls %s -n %s | awk -F ' ' '{print $1 \" \" $5}' | grep '^2' | wc -w" % (image_path, sysroot))
  1123. self.assertEqual('1', result.output)
  1124. @skipIfNotArch(['i586', 'i686', 'x86_64'])
  1125. @OETestTag("runqemu")
  1126. def test_biosplusefi_plugin_qemu(self):
  1127. """Test biosplusefi plugin in qemu"""
  1128. config = 'IMAGE_FSTYPES = "wic"\nWKS_FILE = "test_biosplusefi_plugin.wks"\nMACHINE_FEATURES:append = " efi"\n'
  1129. self.append_config(config)
  1130. bitbake('core-image-minimal')
  1131. self.remove_config(config)
  1132. runqemu_params = get_bb_var('TEST_RUNQEMUPARAMS', 'core-image-minimal') or ""
  1133. with runqemu('core-image-minimal', ssh=False,
  1134. runqemuparams='%s nographic' % (runqemu_params), image_fstype='wic') as qemu:
  1135. # Check that we have ONLY two /dev/sda* partitions (/boot and /)
  1136. cmd = "grep sda. /proc/partitions | wc -l"
  1137. status, output = qemu.run_serial(cmd)
  1138. self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output))
  1139. self.assertEqual(output, '2')
  1140. # Check that /dev/sda1 is /boot and that either /dev/root OR /dev/sda2 is /
  1141. cmd = "mount | grep '^/dev/' | cut -f1,3 -d ' ' | egrep -c -e '/dev/sda1 /boot' -e '/dev/root /|/dev/sda2 /'"
  1142. status, output = qemu.run_serial(cmd)
  1143. self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output))
  1144. self.assertEqual(output, '2')
  1145. # Check that /boot has EFI bootx64.efi (required for EFI)
  1146. cmd = "ls /boot/EFI/BOOT/bootx64.efi | wc -l"
  1147. status, output = qemu.run_serial(cmd)
  1148. self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output))
  1149. self.assertEqual(output, '1')
  1150. # Check that "BOOTABLE" flag is set on boot partition (required for PC-Bios)
  1151. # Trailing "cat" seems to be required; otherwise run_serial() sends back echo of the input command
  1152. cmd = "fdisk -l /dev/sda | grep /dev/sda1 | awk {print'$2'} | cat"
  1153. status, output = qemu.run_serial(cmd)
  1154. self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output))
  1155. self.assertEqual(output, '*')
  1156. @skipIfNotArch(['i586', 'i686', 'x86_64'])
  1157. def test_biosplusefi_plugin(self):
  1158. """Test biosplusefi plugin"""
  1159. # Wic generation below may fail depending on the order of the unittests
  1160. # This is because bootimg-pcbios (that bootimg-biosplusefi uses) generate its MBR inside STAGING_DATADIR directory
  1161. # which may or may not exists depending on what was built already
  1162. # If an image hasn't been built yet, directory ${STAGING_DATADIR}/syslinux won't exists and _get_bootimg_dir()
  1163. # will raise with "Couldn't find correct bootimg_dir"
  1164. # The easiest way to work-around this issue is to make sure we already built an image here, hence the bitbake call
  1165. config = 'IMAGE_FSTYPES = "wic"\nWKS_FILE = "test_biosplusefi_plugin.wks"\nMACHINE_FEATURES:append = " efi"\n'
  1166. self.append_config(config)
  1167. bitbake('core-image-minimal')
  1168. self.remove_config(config)
  1169. img = 'core-image-minimal'
  1170. with NamedTemporaryFile("w", suffix=".wks") as wks:
  1171. wks.writelines(['part /boot --active --source bootimg-biosplusefi --sourceparams="loader=grub-efi"\n',
  1172. 'part / --source rootfs --fstype=ext4 --align 1024 --use-uuid\n'\
  1173. 'bootloader --timeout=0 --append="console=ttyS0,115200n8"\n'])
  1174. wks.flush()
  1175. cmd = "wic create %s -e %s -o %s" % (wks.name, img, self.resultdir)
  1176. runCmd(cmd)
  1177. wksname = os.path.splitext(os.path.basename(wks.name))[0]
  1178. out = glob(os.path.join(self.resultdir, "%s-*.direct" % wksname))
  1179. self.assertEqual(1, len(out))
  1180. @skipIfNotArch(['i586', 'i686', 'x86_64', 'aarch64'])
  1181. def test_uefi_kernel(self):
  1182. """ Test uefi-kernel in wic """
  1183. config = 'IMAGE_EFI_BOOT_FILES="/etc/fstab;testfile"\nIMAGE_FSTYPES = "wic"\nWKS_FILE = "test_uefikernel.wks"\nMACHINE_FEATURES:append = " efi"\n'
  1184. self.append_config(config)
  1185. bitbake('core-image-minimal')
  1186. self.remove_config(config)
  1187. img = 'core-image-minimal'
  1188. with NamedTemporaryFile("w", suffix=".wks") as wks:
  1189. wks.writelines(['part /boot --source bootimg-efi --sourceparams="loader=uefi-kernel"\n'
  1190. 'part / --source rootfs --fstype=ext4 --align 1024 --use-uuid\n'\
  1191. 'bootloader --timeout=0 --append="console=ttyS0,115200n8"\n'])
  1192. wks.flush()
  1193. cmd = "wic create %s -e %s -o %s" % (wks.name, img, self.resultdir)
  1194. runCmd(cmd)
  1195. wksname = os.path.splitext(os.path.basename(wks.name))[0]
  1196. out = glob(os.path.join(self.resultdir, "%s-*.direct" % wksname))
  1197. self.assertEqual(1, len(out))
  1198. # TODO this test could also work on aarch64
  1199. @skipIfNotArch(['i586', 'i686', 'x86_64'])
  1200. @OETestTag("runqemu")
  1201. def test_efi_plugin_unified_kernel_image_qemu(self):
  1202. """Test Unified Kernel Image feature in qemu without systemd in initramfs or rootfs"""
  1203. config = """
  1204. # efi firmware must load systemd-boot, not grub
  1205. EFI_PROVIDER = "systemd-boot"
  1206. # image format must be wic, needs esp partition for firmware etc
  1207. IMAGE_FSTYPES:pn-core-image-base:append = " wic"
  1208. WKS_FILE = "test_efi_plugin.wks"
  1209. # efi, uki and systemd features must be enabled
  1210. MACHINE_FEATURES:append = " efi"
  1211. IMAGE_CLASSES:append:pn-core-image-base = " uki"
  1212. # uki embeds also an initrd, no systemd or udev
  1213. INITRAMFS_IMAGE = "core-image-initramfs-boot"
  1214. # runqemu must not load kernel separately, it's in the uki
  1215. QB_KERNEL_ROOT = ""
  1216. QB_DEFAULT_KERNEL = "none"
  1217. # boot command line provided via uki, not via bootloader
  1218. UKI_CMDLINE = "rootwait root=LABEL=root console=${KERNEL_CONSOLE}"
  1219. """
  1220. self.append_config(config)
  1221. bitbake('core-image-base ovmf')
  1222. runqemu_params = get_bb_var('TEST_RUNQEMUPARAMS', 'core-image-base') or ""
  1223. uki_filename = get_bb_var('UKI_FILENAME', 'core-image-base')
  1224. self.remove_config(config)
  1225. with runqemu('core-image-base', ssh=False,
  1226. runqemuparams='%s nographic ovmf' % (runqemu_params), image_fstype='wic') as qemu:
  1227. # Check that /boot has EFI boot*.efi (required for EFI)
  1228. cmd = "ls /boot/EFI/BOOT/boot*.efi | wc -l"
  1229. status, output = qemu.run_serial(cmd)
  1230. self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output))
  1231. self.assertEqual(output, '1')
  1232. # Check that /boot has EFI/Linux/${UKI_FILENAME} (required for Unified Kernel Images auto detection)
  1233. cmd = "ls /boot/EFI/Linux/%s | wc -l" % (uki_filename)
  1234. status, output = qemu.run_serial(cmd)
  1235. self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output))
  1236. self.assertEqual(output, '1')
  1237. # Check that /boot doesn't have loader/entries/boot.conf (Unified Kernel Images are auto detected by the bootloader)
  1238. cmd = "ls /boot/loader/entries/boot.conf 2&>/dev/null | wc -l"
  1239. status, output = qemu.run_serial(cmd)
  1240. self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output))
  1241. self.assertEqual(output, '0')
  1242. @skipIfNotArch(['aarch64'])
  1243. @OETestTag("runqemu")
  1244. def test_efi_plugin_plain_systemd_boot_qemu_aarch64(self):
  1245. """Test plain systemd-boot in qemu with systemd"""
  1246. config = """
  1247. INIT_MANAGER = "systemd"
  1248. EFI_PROVIDER = "systemd-boot"
  1249. # image format must be wic, needs esp partition for firmware etc
  1250. IMAGE_FSTYPES:pn-core-image-base:append = " wic"
  1251. WKS_FILE = "test_efi_plugin_plain_systemd-boot.wks"
  1252. INITRAMFS_IMAGE = "core-image-initramfs-boot"
  1253. # to configure runqemu
  1254. IMAGE_CLASSES += "qemuboot"
  1255. # u-boot efi firmware
  1256. QB_DEFAULT_BIOS = "u-boot.bin"
  1257. # need to use virtio, scsi not supported by u-boot by default
  1258. QB_DRIVE_TYPE = "/dev/vd"
  1259. # disable kvm, breaks boot
  1260. QEMU_USE_KVM = ""
  1261. IMAGE_CLASSES:remove = 'testimage'
  1262. """
  1263. self.append_config(config)
  1264. bitbake('core-image-base u-boot')
  1265. runqemu_params = get_bb_var('TEST_RUNQEMUPARAMS', 'core-image-base') or ""
  1266. with runqemu('core-image-base', ssh=False,
  1267. runqemuparams='%s nographic' % (runqemu_params), image_fstype='wic') as qemu:
  1268. # Check that /boot has EFI boot*.efi (required for EFI)
  1269. cmd = "ls /boot/EFI/BOOT/boot*.efi | wc -l"
  1270. status, output = qemu.run_serial(cmd)
  1271. self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output))
  1272. self.assertEqual(output, '1')
  1273. # Check that boot.conf exists
  1274. cmd = "cat /boot/loader/entries/boot.conf"
  1275. status, output = qemu.run_serial(cmd)
  1276. self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output))
  1277. self.remove_config(config)
  1278. @skipIfNotArch(['i586', 'i686', 'x86_64'])
  1279. @OETestTag("runqemu")
  1280. def test_efi_plugin_plain_systemd_boot_qemu_x86(self):
  1281. """Test plain systemd-boot to systemd in qemu"""
  1282. config = """
  1283. INIT_MANAGER = "systemd"
  1284. EFI_PROVIDER = "systemd-boot"
  1285. # image format must be wic, needs esp partition for firmware etc
  1286. IMAGE_FSTYPES:pn-core-image-base:append = " wic"
  1287. WKS_FILE = "test_efi_plugin_plain_systemd-boot.wks"
  1288. INITRAMFS_IMAGE = "core-image-initramfs-boot"
  1289. """
  1290. self.append_config(config)
  1291. bitbake('core-image-base ovmf')
  1292. runqemu_params = get_bb_var('TEST_RUNQEMUPARAMS', 'core-image-base') or ""
  1293. self.remove_config(config)
  1294. with runqemu('core-image-base', ssh=False,
  1295. runqemuparams='%s nographic ovmf' % (runqemu_params), image_fstype='wic') as qemu:
  1296. # Check that /boot has EFI boot*.efi (required for EFI)
  1297. cmd = "ls /boot/EFI/BOOT/boot*.efi | wc -l"
  1298. status, output = qemu.run_serial(cmd)
  1299. self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output))
  1300. self.assertEqual(output, '1')
  1301. # Check that boot.conf exists
  1302. cmd = "cat /boot/loader/entries/boot.conf"
  1303. status, output = qemu.run_serial(cmd)
  1304. self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output))
  1305. def test_fs_types(self):
  1306. """Test filesystem types for empty and not empty partitions"""
  1307. img = 'core-image-minimal'
  1308. with NamedTemporaryFile("w", suffix=".wks") as wks:
  1309. wks.writelines(['part ext2 --fstype ext2 --source rootfs\n',
  1310. 'part btrfs --fstype btrfs --source rootfs --size 40M\n',
  1311. 'part squash --fstype squashfs --source rootfs\n',
  1312. 'part swap --fstype swap --size 1M\n',
  1313. 'part emptyvfat --fstype vfat --size 1M\n',
  1314. 'part emptymsdos --fstype msdos --size 1M\n',
  1315. 'part emptyext2 --fstype ext2 --size 1M\n',
  1316. 'part emptybtrfs --fstype btrfs --size 150M\n'])
  1317. wks.flush()
  1318. cmd = "wic create %s -e %s -o %s" % (wks.name, img, self.resultdir)
  1319. runCmd(cmd)
  1320. wksname = os.path.splitext(os.path.basename(wks.name))[0]
  1321. out = glob(os.path.join(self.resultdir, "%s-*direct" % wksname))
  1322. self.assertEqual(1, len(out))
  1323. def test_kickstart_parser(self):
  1324. """Test wks parser options"""
  1325. with NamedTemporaryFile("w", suffix=".wks") as wks:
  1326. wks.writelines(['part / --fstype ext3 --source rootfs --system-id 0xFF '\
  1327. '--overhead-factor 1.2 --size 100k\n'])
  1328. wks.flush()
  1329. cmd = "wic create %s -e core-image-minimal -o %s" % (wks.name, self.resultdir)
  1330. runCmd(cmd)
  1331. wksname = os.path.splitext(os.path.basename(wks.name))[0]
  1332. out = glob(os.path.join(self.resultdir, "%s-*direct" % wksname))
  1333. self.assertEqual(1, len(out))
  1334. def test_image_bootpart_globbed(self):
  1335. """Test globbed sources with image-bootpart plugin"""
  1336. img = "core-image-minimal"
  1337. cmd = "wic create sdimage-bootpart -e %s -o %s" % (img, self.resultdir)
  1338. config = 'IMAGE_BOOT_FILES = "%s*"' % get_bb_var('KERNEL_IMAGETYPE', img)
  1339. self.append_config(config)
  1340. runCmd(cmd)
  1341. self.remove_config(config)
  1342. self.assertEqual(1, len(glob(os.path.join(self.resultdir, "sdimage-bootpart-*direct"))))
  1343. def test_sparse_copy(self):
  1344. """Test sparse_copy with FIEMAP and SEEK_HOLE filemap APIs"""
  1345. libpath = os.path.join(self.td['COREBASE'], 'scripts', 'lib', 'wic')
  1346. sys.path.insert(0, libpath)
  1347. from filemap import FilemapFiemap, FilemapSeek, sparse_copy, ErrorNotSupp
  1348. with NamedTemporaryFile("w", suffix=".wic-sparse") as sparse:
  1349. src_name = sparse.name
  1350. src_size = 1024 * 10
  1351. sparse.truncate(src_size)
  1352. # write one byte to the file
  1353. with open(src_name, 'r+b') as sfile:
  1354. sfile.seek(1024 * 4)
  1355. sfile.write(b'\x00')
  1356. dest = sparse.name + '.out'
  1357. # copy src file to dest using different filemap APIs
  1358. for api in (FilemapFiemap, FilemapSeek, None):
  1359. if os.path.exists(dest):
  1360. os.unlink(dest)
  1361. try:
  1362. sparse_copy(sparse.name, dest, api=api)
  1363. except ErrorNotSupp:
  1364. continue # skip unsupported API
  1365. dest_stat = os.stat(dest)
  1366. self.assertEqual(dest_stat.st_size, src_size)
  1367. # 8 blocks is 4K (physical sector size)
  1368. self.assertEqual(dest_stat.st_blocks, 8)
  1369. os.unlink(dest)
  1370. def test_mkfs_extraopts(self):
  1371. """Test wks option --mkfs-extraopts for empty and not empty partitions"""
  1372. img = 'core-image-minimal'
  1373. with NamedTemporaryFile("w", suffix=".wks") as wks:
  1374. wks.writelines(
  1375. ['part ext2 --fstype ext2 --source rootfs --mkfs-extraopts "-D -F -i 8192"\n',
  1376. "part btrfs --fstype btrfs --source rootfs --size 40M --mkfs-extraopts='--quiet'\n",
  1377. 'part squash --fstype squashfs --source rootfs --mkfs-extraopts "-no-sparse -b 4096"\n',
  1378. 'part emptyvfat --fstype vfat --size 1M --mkfs-extraopts "-S 1024 -s 64"\n',
  1379. 'part emptymsdos --fstype msdos --size 1M --mkfs-extraopts "-S 1024 -s 64"\n',
  1380. 'part emptyext2 --fstype ext2 --size 1M --mkfs-extraopts "-D -F -i 8192"\n',
  1381. 'part emptybtrfs --fstype btrfs --size 100M --mkfs-extraopts "--mixed -K"\n'])
  1382. wks.flush()
  1383. cmd = "wic create %s -e %s -o %s" % (wks.name, img, self.resultdir)
  1384. runCmd(cmd)
  1385. wksname = os.path.splitext(os.path.basename(wks.name))[0]
  1386. out = glob(os.path.join(self.resultdir, "%s-*direct" % wksname))
  1387. self.assertEqual(1, len(out))
  1388. @skipIfNotArch(['i586', 'i686', 'x86_64'])
  1389. @OETestTag("runqemu")
  1390. def test_expand_mbr_image(self):
  1391. """Test wic write --expand command for mbr image"""
  1392. # build an image
  1393. config = 'IMAGE_FSTYPES = "wic"\nWKS_FILE = "directdisk.wks"\n'
  1394. self.append_config(config)
  1395. image = 'core-image-minimal'
  1396. bitbake(image)
  1397. # get path to the image
  1398. bb_vars = get_bb_vars(['DEPLOY_DIR_IMAGE', 'IMAGE_LINK_NAME'], image)
  1399. image_path = os.path.join(bb_vars['DEPLOY_DIR_IMAGE'], '%s.wic' % bb_vars['IMAGE_LINK_NAME'])
  1400. self.remove_config(config)
  1401. try:
  1402. # expand image to 1G
  1403. new_image_path = None
  1404. with NamedTemporaryFile(mode='wb', suffix='.wic.exp',
  1405. dir=bb_vars['DEPLOY_DIR_IMAGE'], delete=False) as sparse:
  1406. sparse.truncate(1024 ** 3)
  1407. new_image_path = sparse.name
  1408. sysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'wic-tools')
  1409. cmd = "wic write -n %s --expand 1:0 %s %s" % (sysroot, image_path, new_image_path)
  1410. runCmd(cmd)
  1411. # check if partitions are expanded
  1412. orig = runCmd("wic ls %s -n %s" % (image_path, sysroot))
  1413. exp = runCmd("wic ls %s -n %s" % (new_image_path, sysroot))
  1414. orig_sizes = [int(line.split()[3]) for line in orig.output.split('\n')[1:]]
  1415. exp_sizes = [int(line.split()[3]) for line in exp.output.split('\n')[1:]]
  1416. self.assertEqual(orig_sizes[0], exp_sizes[0]) # first partition is not resized
  1417. self.assertTrue(orig_sizes[1] < exp_sizes[1], msg="Parition size wasn't enlarged (%s vs %s)" % (orig_sizes[1], exp_sizes[1]))
  1418. # Check if all free space is partitioned
  1419. result = runCmd("%s/usr/sbin/sfdisk -F %s" % (sysroot, new_image_path))
  1420. self.assertIn("0 B, 0 bytes, 0 sectors", result.output)
  1421. os.rename(image_path, image_path + '.bak')
  1422. os.rename(new_image_path, image_path)
  1423. runqemu_params = get_bb_var('TEST_RUNQEMUPARAMS', 'core-image-minimal') or ""
  1424. with runqemu('core-image-minimal', ssh=False, runqemuparams='%s nographic' % (runqemu_params)) as qemu:
  1425. cmd = "ls /etc/"
  1426. status, output = qemu.run_serial('true')
  1427. self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output))
  1428. finally:
  1429. if os.path.exists(new_image_path):
  1430. os.unlink(new_image_path)
  1431. if os.path.exists(image_path + '.bak'):
  1432. os.rename(image_path + '.bak', image_path)
  1433. def test_gpt_partition_name(self):
  1434. """Test --part-name argument to set partition name in GPT table"""
  1435. config = 'IMAGE_FSTYPES += "wic"\nWKS_FILE = "test_gpt_partition_name.wks"\n'
  1436. self.append_config(config)
  1437. image = 'core-image-minimal'
  1438. bitbake(image)
  1439. self.remove_config(config)
  1440. deploy_dir = get_bb_var('DEPLOY_DIR_IMAGE')
  1441. bb_vars = get_bb_vars(['DEPLOY_DIR_IMAGE', 'IMAGE_LINK_NAME'], image)
  1442. image_path = os.path.join(bb_vars['DEPLOY_DIR_IMAGE'], '%s.wic' % bb_vars['IMAGE_LINK_NAME'])
  1443. sysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'wic-tools')
  1444. # Image is created
  1445. self.assertTrue(os.path.exists(image_path), "image file %s doesn't exist" % image_path)
  1446. # Check the names of the three partitions
  1447. # as listed in test_gpt_partition_name.wks
  1448. result = runCmd("%s/usr/sbin/sfdisk --part-label %s 1" % (sysroot, image_path))
  1449. self.assertEqual('boot-A', result.output)
  1450. result = runCmd("%s/usr/sbin/sfdisk --part-label %s 2" % (sysroot, image_path))
  1451. self.assertEqual('root-A', result.output)
  1452. # When the --part-name is not defined, the partition name is equal to the --label
  1453. result = runCmd("%s/usr/sbin/sfdisk --part-label %s 3" % (sysroot, image_path))
  1454. self.assertEqual('ext-space', result.output)
  1455. def test_empty_zeroize_plugin(self):
  1456. img = 'core-image-minimal'
  1457. expected_size = [ 1024*1024, # 1M
  1458. 512*1024, # 512K
  1459. 2*1024*1024] # 2M
  1460. # Check combination of sourceparams
  1461. with NamedTemporaryFile("w", suffix=".wks") as wks:
  1462. wks.writelines(
  1463. ['part empty --source empty --sourceparams="fill" --ondisk sda --fixed-size 1M\n',
  1464. 'part empty --source empty --sourceparams="size=512K" --ondisk sda --size 1M --align 1024\n',
  1465. 'part empty --source empty --sourceparams="size=2048k,bs=512K" --ondisk sda --size 4M --align 1024\n'
  1466. ])
  1467. wks.flush()
  1468. cmd = "wic create %s -e %s -o %s" % (wks.name, img, self.resultdir)
  1469. runCmd(cmd)
  1470. wksname = os.path.splitext(os.path.basename(wks.name))[0]
  1471. wicout = glob(os.path.join(self.resultdir, "%s-*direct" % wksname))
  1472. # Skip the complete image and just look at the single partitions
  1473. for idx, value in enumerate(wicout[1:]):
  1474. self.logger.info(wicout[idx])
  1475. # Check if partitions are actually zeroized
  1476. with open(wicout[idx], mode="rb") as fd:
  1477. ba = bytearray(fd.read())
  1478. for b in ba:
  1479. self.assertEqual(b, 0)
  1480. self.assertEqual(expected_size[idx], os.path.getsize(wicout[idx]))
  1481. # Check inconsistancy check between "fill" and "--size" parameter
  1482. with NamedTemporaryFile("w", suffix=".wks") as wks:
  1483. wks.writelines(['part empty --source empty --sourceparams="fill" --ondisk sda --size 1M\n'])
  1484. wks.flush()
  1485. cmd = "wic create %s -e %s -o %s" % (wks.name, img, self.resultdir)
  1486. result = runCmd(cmd, ignore_status=True)
  1487. self.assertIn("Source parameter 'fill' only works with the '--fixed-size' option, exiting.", result.output)
  1488. self.assertNotEqual(0, result.status)
  1489. class ModifyTests(WicTestCase):
  1490. def test_wic_ls(self):
  1491. """Test listing image content using 'wic ls'"""
  1492. runCmd("wic create wictestdisk "
  1493. "--image-name=core-image-minimal "
  1494. "-D -o %s" % self.resultdir)
  1495. images = glob(os.path.join(self.resultdir, "wictestdisk-*.direct"))
  1496. self.assertEqual(1, len(images))
  1497. sysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'wic-tools')
  1498. # list partitions
  1499. result = runCmd("wic ls %s -n %s" % (images[0], sysroot))
  1500. self.assertEqual(3, len(result.output.split('\n')))
  1501. # list directory content of the first partition
  1502. result = runCmd("wic ls %s:1/ -n %s" % (images[0], sysroot))
  1503. self.assertEqual(6, len(result.output.split('\n')))
  1504. def test_wic_cp(self):
  1505. """Test copy files and directories to the the wic image."""
  1506. runCmd("wic create wictestdisk "
  1507. "--image-name=core-image-minimal "
  1508. "-D -o %s" % self.resultdir)
  1509. images = glob(os.path.join(self.resultdir, "wictestdisk-*.direct"))
  1510. self.assertEqual(1, len(images))
  1511. sysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'wic-tools')
  1512. # list directory content of the first partition
  1513. result = runCmd("wic ls %s:1/ -n %s" % (images[0], sysroot))
  1514. self.assertEqual(6, len(result.output.split('\n')))
  1515. with NamedTemporaryFile("w", suffix=".wic-cp") as testfile:
  1516. testfile.write("test")
  1517. # copy file to the partition
  1518. runCmd("wic cp %s %s:1/ -n %s" % (testfile.name, images[0], sysroot))
  1519. # check if file is there
  1520. result = runCmd("wic ls %s:1/ -n %s" % (images[0], sysroot))
  1521. self.assertEqual(7, len(result.output.split('\n')))
  1522. self.assertIn(os.path.basename(testfile.name), result.output)
  1523. # prepare directory
  1524. testdir = os.path.join(self.resultdir, 'wic-test-cp-dir')
  1525. testsubdir = os.path.join(testdir, 'subdir')
  1526. os.makedirs(os.path.join(testsubdir))
  1527. copy(testfile.name, testdir)
  1528. # copy directory to the partition
  1529. runCmd("wic cp %s %s:1/ -n %s" % (testdir, images[0], sysroot))
  1530. # check if directory is there
  1531. result = runCmd("wic ls %s:1/ -n %s" % (images[0], sysroot))
  1532. self.assertEqual(8, len(result.output.split('\n')))
  1533. self.assertIn(os.path.basename(testdir), result.output)
  1534. # copy the file from the partition and check if it success
  1535. dest = '%s-cp' % testfile.name
  1536. runCmd("wic cp %s:1/%s %s -n %s" % (images[0],
  1537. os.path.basename(testfile.name), dest, sysroot))
  1538. self.assertTrue(os.path.exists(dest), msg="File %s wasn't generated as expected" % dest)
  1539. def test_wic_rm(self):
  1540. """Test removing files and directories from the the wic image."""
  1541. runCmd("wic create mkefidisk "
  1542. "--image-name=core-image-minimal "
  1543. "-D -o %s" % self.resultdir)
  1544. images = glob(os.path.join(self.resultdir, "mkefidisk-*.direct"))
  1545. self.assertEqual(1, len(images))
  1546. sysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'wic-tools')
  1547. # Not bulletproof but hopefully sufficient
  1548. kerneltype = get_bb_var('KERNEL_IMAGETYPE', 'virtual/kernel')
  1549. # list directory content of the first partition
  1550. result = runCmd("wic ls %s:1 -n %s" % (images[0], sysroot))
  1551. self.assertIn('\n%s ' % kerneltype.upper(), result.output)
  1552. self.assertIn('\nEFI <DIR> ', result.output)
  1553. # remove file. EFI partitions are case-insensitive so exercise that too
  1554. runCmd("wic rm %s:1/%s -n %s" % (images[0], kerneltype.lower(), sysroot))
  1555. # remove directory
  1556. runCmd("wic rm %s:1/efi -n %s" % (images[0], sysroot))
  1557. # check if they're removed
  1558. result = runCmd("wic ls %s:1 -n %s" % (images[0], sysroot))
  1559. self.assertNotIn('\n%s ' % kerneltype.upper(), result.output)
  1560. self.assertNotIn('\nEFI <DIR> ', result.output)
  1561. def test_wic_ls_ext(self):
  1562. """Test listing content of the ext partition using 'wic ls'"""
  1563. runCmd("wic create wictestdisk "
  1564. "--image-name=core-image-minimal "
  1565. "-D -o %s" % self.resultdir)
  1566. images = glob(os.path.join(self.resultdir, "wictestdisk-*.direct"))
  1567. self.assertEqual(1, len(images))
  1568. sysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'wic-tools')
  1569. # list directory content of the second ext4 partition
  1570. result = runCmd("wic ls %s:2/ -n %s" % (images[0], sysroot))
  1571. self.assertTrue(set(['bin', 'home', 'proc', 'usr', 'var', 'dev', 'lib', 'sbin']).issubset(
  1572. set(line.split()[-1] for line in result.output.split('\n') if line)), msg="Expected directories not present %s" % result.output)
  1573. def test_wic_cp_ext(self):
  1574. """Test copy files and directories to the ext partition."""
  1575. runCmd("wic create wictestdisk "
  1576. "--image-name=core-image-minimal "
  1577. "-D -o %s" % self.resultdir)
  1578. images = glob(os.path.join(self.resultdir, "wictestdisk-*.direct"))
  1579. self.assertEqual(1, len(images))
  1580. sysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'wic-tools')
  1581. # list directory content of the ext4 partition
  1582. result = runCmd("wic ls %s:2/ -n %s" % (images[0], sysroot))
  1583. dirs = set(line.split()[-1] for line in result.output.split('\n') if line)
  1584. self.assertTrue(set(['bin', 'home', 'proc', 'usr', 'var', 'dev', 'lib', 'sbin']).issubset(dirs), msg="Expected directories not present %s" % dirs)
  1585. with NamedTemporaryFile("w", suffix=".wic-cp") as testfile:
  1586. testfile.write("test")
  1587. # copy file to the partition
  1588. runCmd("wic cp %s %s:2/ -n %s" % (testfile.name, images[0], sysroot))
  1589. # check if file is there
  1590. result = runCmd("wic ls %s:2/ -n %s" % (images[0], sysroot))
  1591. newdirs = set(line.split()[-1] for line in result.output.split('\n') if line)
  1592. self.assertEqual(newdirs.difference(dirs), set([os.path.basename(testfile.name)]))
  1593. # check if the file to copy is in the partition
  1594. result = runCmd("wic ls %s:2/etc/ -n %s" % (images[0], sysroot))
  1595. self.assertIn('fstab', [line.split()[-1] for line in result.output.split('\n') if line])
  1596. # copy file from the partition, replace the temporary file content with it and
  1597. # check for the file size to validate the copy
  1598. runCmd("wic cp %s:2/etc/fstab %s -n %s" % (images[0], testfile.name, sysroot))
  1599. self.assertTrue(os.stat(testfile.name).st_size > 0, msg="Filesize not as expected %s" % os.stat(testfile.name).st_size)
  1600. def test_wic_rm_ext(self):
  1601. """Test removing files from the ext partition."""
  1602. runCmd("wic create mkefidisk "
  1603. "--image-name=core-image-minimal "
  1604. "-D -o %s" % self.resultdir)
  1605. images = glob(os.path.join(self.resultdir, "mkefidisk-*.direct"))
  1606. self.assertEqual(1, len(images))
  1607. sysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'wic-tools')
  1608. # list directory content of the /etc directory on ext4 partition
  1609. result = runCmd("wic ls %s:2/etc/ -n %s" % (images[0], sysroot))
  1610. self.assertIn('fstab', [line.split()[-1] for line in result.output.split('\n') if line])
  1611. # remove file
  1612. runCmd("wic rm %s:2/etc/fstab -n %s" % (images[0], sysroot))
  1613. # check if it's removed
  1614. result = runCmd("wic ls %s:2/etc/ -n %s" % (images[0], sysroot))
  1615. self.assertNotIn('fstab', [line.split()[-1] for line in result.output.split('\n') if line])
  1616. # remove non-empty directory
  1617. runCmd("wic rm -r %s:2/etc/ -n %s" % (images[0], sysroot))
  1618. # check if it's removed
  1619. result = runCmd("wic ls %s:2/ -n %s" % (images[0], sysroot))
  1620. self.assertNotIn('etc', [line.split()[-1] for line in result.output.split('\n') if line])