wic.py 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982
  1. #!/usr/bin/env python
  2. # ex:ts=4:sw=4:sts=4:et
  3. # -*- tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*-
  4. #
  5. # Copyright (c) 2015, Intel Corporation.
  6. # All rights reserved.
  7. #
  8. # This program is free software; you can redistribute it and/or modify
  9. # it under the terms of the GNU General Public License version 2 as
  10. # published by the Free Software Foundation.
  11. #
  12. # This program is distributed in the hope that it will be useful,
  13. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. # GNU General Public License for more details.
  16. #
  17. # You should have received a copy of the GNU General Public License along
  18. # with this program; if not, write to the Free Software Foundation, Inc.,
  19. # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  20. #
  21. # AUTHORS
  22. # Ed Bartosh <ed.bartosh@linux.intel.com>
  23. """Test cases for wic."""
  24. import os
  25. import sys
  26. import unittest
  27. from glob import glob
  28. from shutil import rmtree, copy
  29. from functools import wraps, lru_cache
  30. from tempfile import NamedTemporaryFile
  31. from oeqa.selftest.case import OESelftestTestCase
  32. from oeqa.utils.commands import runCmd, bitbake, get_bb_var, get_bb_vars, runqemu
  33. @lru_cache(maxsize=32)
  34. def get_host_arch(recipe):
  35. """A cached call to get_bb_var('HOST_ARCH', <recipe>)"""
  36. return get_bb_var('HOST_ARCH', recipe)
  37. def only_for_arch(archs, image='core-image-minimal'):
  38. """Decorator for wrapping test cases that can be run only for specific target
  39. architectures. A list of compatible architectures is passed in `archs`.
  40. Current architecture will be determined by parsing bitbake output for
  41. `image` recipe.
  42. """
  43. def wrapper(func):
  44. @wraps(func)
  45. def wrapped_f(*args, **kwargs):
  46. arch = get_host_arch(image)
  47. if archs and arch not in archs:
  48. raise unittest.SkipTest("Testcase arch dependency not met: %s" % arch)
  49. return func(*args, **kwargs)
  50. wrapped_f.__name__ = func.__name__
  51. return wrapped_f
  52. return wrapper
  53. class WicTestCase(OESelftestTestCase):
  54. """Wic test class."""
  55. image_is_ready = False
  56. wicenv_cache = {}
  57. def setUpLocal(self):
  58. """This code is executed before each test method."""
  59. self.resultdir = self.builddir + "/wic-tmp/"
  60. super(WicTestCase, self).setUpLocal()
  61. # Do this here instead of in setUpClass as the base setUp does some
  62. # clean up which can result in the native tools built earlier in
  63. # setUpClass being unavailable.
  64. if not WicTestCase.image_is_ready:
  65. if get_bb_var('USE_NLS') == 'yes':
  66. bitbake('wic-tools')
  67. else:
  68. self.skipTest('wic-tools cannot be built due its (intltool|gettext)-native dependency and NLS disable')
  69. bitbake('core-image-minimal')
  70. WicTestCase.image_is_ready = True
  71. rmtree(self.resultdir, ignore_errors=True)
  72. def tearDownLocal(self):
  73. """Remove resultdir as it may contain images."""
  74. rmtree(self.resultdir, ignore_errors=True)
  75. super(WicTestCase, self).tearDownLocal()
  76. def _get_image_env_path(self, image):
  77. """Generate and obtain the path to <image>.env"""
  78. if image not in WicTestCase.wicenv_cache:
  79. self.assertEqual(0, bitbake('%s -c do_rootfs_wicenv' % image).status)
  80. bb_vars = get_bb_vars(['STAGING_DIR', 'MACHINE'], image)
  81. stdir = bb_vars['STAGING_DIR']
  82. machine = bb_vars['MACHINE']
  83. WicTestCase.wicenv_cache[image] = os.path.join(stdir, machine, 'imgdata')
  84. return WicTestCase.wicenv_cache[image]
  85. class Wic(WicTestCase):
  86. def test_version(self):
  87. """Test wic --version"""
  88. runCmd('wic --version')
  89. def test_help(self):
  90. """Test wic --help and wic -h"""
  91. runCmd('wic --help')
  92. runCmd('wic -h')
  93. def test_createhelp(self):
  94. """Test wic create --help"""
  95. runCmd('wic create --help')
  96. def test_listhelp(self):
  97. """Test wic list --help"""
  98. runCmd('wic list --help')
  99. def test_help_create(self):
  100. """Test wic help create"""
  101. runCmd('wic help create')
  102. def test_help_list(self):
  103. """Test wic help list"""
  104. runCmd('wic help list')
  105. def test_help_overview(self):
  106. """Test wic help overview"""
  107. runCmd('wic help overview')
  108. def test_help_plugins(self):
  109. """Test wic help plugins"""
  110. runCmd('wic help plugins')
  111. def test_help_kickstart(self):
  112. """Test wic help kickstart"""
  113. runCmd('wic help kickstart')
  114. def test_list_images(self):
  115. """Test wic list images"""
  116. runCmd('wic list images')
  117. def test_list_source_plugins(self):
  118. """Test wic list source-plugins"""
  119. runCmd('wic list source-plugins')
  120. def test_listed_images_help(self):
  121. """Test wic listed images help"""
  122. output = runCmd('wic list images').output
  123. imagelist = [line.split()[0] for line in output.splitlines()]
  124. for image in imagelist:
  125. runCmd('wic list %s help' % image)
  126. def test_unsupported_subcommand(self):
  127. """Test unsupported subcommand"""
  128. self.assertNotEqual(0, runCmd('wic unsupported', ignore_status=True).status)
  129. def test_no_command(self):
  130. """Test wic without command"""
  131. self.assertEqual(1, runCmd('wic', ignore_status=True).status)
  132. def test_build_image_name(self):
  133. """Test wic create wictestdisk --image-name=core-image-minimal"""
  134. cmd = "wic create wictestdisk --image-name=core-image-minimal -o %s" % self.resultdir
  135. runCmd(cmd)
  136. self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*.direct")))
  137. @only_for_arch(['i586', 'i686', 'x86_64'])
  138. def test_gpt_image(self):
  139. """Test creation of core-image-minimal with gpt table and UUID boot"""
  140. cmd = "wic create directdisk-gpt --image-name core-image-minimal -o %s" % self.resultdir
  141. runCmd(cmd)
  142. self.assertEqual(1, len(glob(self.resultdir + "directdisk-*.direct")))
  143. @only_for_arch(['i586', 'i686', 'x86_64'])
  144. def test_iso_image(self):
  145. """Test creation of hybrid iso image with legacy and EFI boot"""
  146. config = 'INITRAMFS_IMAGE = "core-image-minimal-initramfs"\n'\
  147. 'MACHINE_FEATURES_append = " efi"\n'\
  148. 'DEPENDS_pn-core-image-minimal += "syslinux"\n'
  149. self.append_config(config)
  150. bitbake('core-image-minimal core-image-minimal-initramfs')
  151. self.remove_config(config)
  152. cmd = "wic create mkhybridiso --image-name core-image-minimal -o %s" % self.resultdir
  153. runCmd(cmd)
  154. self.assertEqual(1, len(glob(self.resultdir + "HYBRID_ISO_IMG-*.direct")))
  155. self.assertEqual(1, len(glob(self.resultdir + "HYBRID_ISO_IMG-*.iso")))
  156. @only_for_arch(['i586', 'i686', 'x86_64'])
  157. def test_qemux86_directdisk(self):
  158. """Test creation of qemux-86-directdisk image"""
  159. cmd = "wic create qemux86-directdisk -e core-image-minimal -o %s" % self.resultdir
  160. runCmd(cmd)
  161. self.assertEqual(1, len(glob(self.resultdir + "qemux86-directdisk-*direct")))
  162. @only_for_arch(['i586', 'i686', 'x86_64'])
  163. def test_mkefidisk(self):
  164. """Test creation of mkefidisk image"""
  165. cmd = "wic create mkefidisk -e core-image-minimal -o %s" % self.resultdir
  166. runCmd(cmd)
  167. self.assertEqual(1, len(glob(self.resultdir + "mkefidisk-*direct")))
  168. @only_for_arch(['i586', 'i686', 'x86_64'])
  169. def test_bootloader_config(self):
  170. """Test creation of directdisk-bootloader-config image"""
  171. config = 'DEPENDS_pn-core-image-minimal += "syslinux"\n'
  172. self.append_config(config)
  173. bitbake('core-image-minimal')
  174. self.remove_config(config)
  175. cmd = "wic create directdisk-bootloader-config -e core-image-minimal -o %s" % self.resultdir
  176. runCmd(cmd)
  177. self.assertEqual(1, len(glob(self.resultdir + "directdisk-bootloader-config-*direct")))
  178. @only_for_arch(['i586', 'i686', 'x86_64'])
  179. def test_systemd_bootdisk(self):
  180. """Test creation of systemd-bootdisk image"""
  181. config = 'MACHINE_FEATURES_append = " efi"\n'
  182. self.append_config(config)
  183. bitbake('core-image-minimal')
  184. self.remove_config(config)
  185. cmd = "wic create systemd-bootdisk -e core-image-minimal -o %s" % self.resultdir
  186. runCmd(cmd)
  187. self.assertEqual(1, len(glob(self.resultdir + "systemd-bootdisk-*direct")))
  188. def test_sdimage_bootpart(self):
  189. """Test creation of sdimage-bootpart image"""
  190. cmd = "wic create sdimage-bootpart -e core-image-minimal -o %s" % self.resultdir
  191. kimgtype = get_bb_var('KERNEL_IMAGETYPE', 'core-image-minimal')
  192. self.write_config('IMAGE_BOOT_FILES = "%s"\n' % kimgtype)
  193. runCmd(cmd)
  194. self.assertEqual(1, len(glob(self.resultdir + "sdimage-bootpart-*direct")))
  195. @only_for_arch(['i586', 'i686', 'x86_64'])
  196. def test_default_output_dir(self):
  197. """Test default output location"""
  198. for fname in glob("directdisk-*.direct"):
  199. os.remove(fname)
  200. config = 'DEPENDS_pn-core-image-minimal += "syslinux"\n'
  201. self.append_config(config)
  202. bitbake('core-image-minimal')
  203. self.remove_config(config)
  204. cmd = "wic create directdisk -e core-image-minimal"
  205. runCmd(cmd)
  206. self.assertEqual(1, len(glob("directdisk-*.direct")))
  207. @only_for_arch(['i586', 'i686', 'x86_64'])
  208. def test_build_artifacts(self):
  209. """Test wic create directdisk providing all artifacts."""
  210. bb_vars = get_bb_vars(['STAGING_DATADIR', 'RECIPE_SYSROOT_NATIVE'],
  211. 'wic-tools')
  212. bb_vars.update(get_bb_vars(['DEPLOY_DIR_IMAGE', 'IMAGE_ROOTFS'],
  213. 'core-image-minimal'))
  214. bbvars = {key.lower(): value for key, value in bb_vars.items()}
  215. bbvars['resultdir'] = self.resultdir
  216. runCmd("wic create directdisk "
  217. "-b %(staging_datadir)s "
  218. "-k %(deploy_dir_image)s "
  219. "-n %(recipe_sysroot_native)s "
  220. "-r %(image_rootfs)s "
  221. "-o %(resultdir)s" % bbvars)
  222. self.assertEqual(1, len(glob(self.resultdir + "directdisk-*.direct")))
  223. def test_compress_gzip(self):
  224. """Test compressing an image with gzip"""
  225. runCmd("wic create wictestdisk "
  226. "--image-name core-image-minimal "
  227. "-c gzip -o %s" % self.resultdir)
  228. self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*.direct.gz")))
  229. def test_compress_bzip2(self):
  230. """Test compressing an image with bzip2"""
  231. runCmd("wic create wictestdisk "
  232. "--image-name=core-image-minimal "
  233. "-c bzip2 -o %s" % self.resultdir)
  234. self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*.direct.bz2")))
  235. def test_compress_xz(self):
  236. """Test compressing an image with xz"""
  237. runCmd("wic create wictestdisk "
  238. "--image-name=core-image-minimal "
  239. "--compress-with=xz -o %s" % self.resultdir)
  240. self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*.direct.xz")))
  241. def test_wrong_compressor(self):
  242. """Test how wic breaks if wrong compressor is provided"""
  243. self.assertEqual(2, runCmd("wic create wictestdisk "
  244. "--image-name=core-image-minimal "
  245. "-c wrong -o %s" % self.resultdir,
  246. ignore_status=True).status)
  247. def test_debug_short(self):
  248. """Test -D option"""
  249. runCmd("wic create wictestdisk "
  250. "--image-name=core-image-minimal "
  251. "-D -o %s" % self.resultdir)
  252. self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*.direct")))
  253. def test_debug_long(self):
  254. """Test --debug option"""
  255. runCmd("wic create wictestdisk "
  256. "--image-name=core-image-minimal "
  257. "--debug -o %s" % self.resultdir)
  258. self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*.direct")))
  259. def test_skip_build_check_short(self):
  260. """Test -s option"""
  261. runCmd("wic create wictestdisk "
  262. "--image-name=core-image-minimal "
  263. "-s -o %s" % self.resultdir)
  264. self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*.direct")))
  265. def test_skip_build_check_long(self):
  266. """Test --skip-build-check option"""
  267. runCmd("wic create wictestdisk "
  268. "--image-name=core-image-minimal "
  269. "--skip-build-check "
  270. "--outdir %s" % self.resultdir)
  271. self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*.direct")))
  272. def test_build_rootfs_short(self):
  273. """Test -f option"""
  274. runCmd("wic create wictestdisk "
  275. "--image-name=core-image-minimal "
  276. "-f -o %s" % self.resultdir)
  277. self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*.direct")))
  278. def test_build_rootfs_long(self):
  279. """Test --build-rootfs option"""
  280. runCmd("wic create wictestdisk "
  281. "--image-name=core-image-minimal "
  282. "--build-rootfs "
  283. "--outdir %s" % self.resultdir)
  284. self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*.direct")))
  285. @only_for_arch(['i586', 'i686', 'x86_64'])
  286. def test_rootfs_indirect_recipes(self):
  287. """Test usage of rootfs plugin with rootfs recipes"""
  288. runCmd("wic create directdisk-multi-rootfs "
  289. "--image-name=core-image-minimal "
  290. "--rootfs rootfs1=core-image-minimal "
  291. "--rootfs rootfs2=core-image-minimal "
  292. "--outdir %s" % self.resultdir)
  293. self.assertEqual(1, len(glob(self.resultdir + "directdisk-multi-rootfs*.direct")))
  294. @only_for_arch(['i586', 'i686', 'x86_64'])
  295. def test_rootfs_artifacts(self):
  296. """Test usage of rootfs plugin with rootfs paths"""
  297. bb_vars = get_bb_vars(['STAGING_DATADIR', 'RECIPE_SYSROOT_NATIVE'],
  298. 'wic-tools')
  299. bb_vars.update(get_bb_vars(['DEPLOY_DIR_IMAGE', 'IMAGE_ROOTFS'],
  300. 'core-image-minimal'))
  301. bbvars = {key.lower(): value for key, value in bb_vars.items()}
  302. bbvars['wks'] = "directdisk-multi-rootfs"
  303. bbvars['resultdir'] = self.resultdir
  304. runCmd("wic create %(wks)s "
  305. "--bootimg-dir=%(staging_datadir)s "
  306. "--kernel-dir=%(deploy_dir_image)s "
  307. "--native-sysroot=%(recipe_sysroot_native)s "
  308. "--rootfs-dir rootfs1=%(image_rootfs)s "
  309. "--rootfs-dir rootfs2=%(image_rootfs)s "
  310. "--outdir %(resultdir)s" % bbvars)
  311. self.assertEqual(1, len(glob(self.resultdir + "%(wks)s-*.direct" % bbvars)))
  312. def test_exclude_path(self):
  313. """Test --exclude-path wks option."""
  314. oldpath = os.environ['PATH']
  315. os.environ['PATH'] = get_bb_var("PATH", "wic-tools")
  316. try:
  317. wks_file = 'temp.wks'
  318. with open(wks_file, 'w') as wks:
  319. rootfs_dir = get_bb_var('IMAGE_ROOTFS', 'core-image-minimal')
  320. wks.write("""
  321. part / --source rootfs --ondisk mmcblk0 --fstype=ext4 --exclude-path usr
  322. part /usr --source rootfs --ondisk mmcblk0 --fstype=ext4 --rootfs-dir %s/usr
  323. part /etc --source rootfs --ondisk mmcblk0 --fstype=ext4 --exclude-path bin/ --rootfs-dir %s/usr"""
  324. % (rootfs_dir, rootfs_dir))
  325. runCmd("wic create %s -e core-image-minimal -o %s" \
  326. % (wks_file, self.resultdir))
  327. os.remove(wks_file)
  328. wicout = glob(self.resultdir + "%s-*direct" % 'temp')
  329. self.assertEqual(1, len(wicout))
  330. wicimg = wicout[0]
  331. # verify partition size with wic
  332. res = runCmd("parted -m %s unit b p 2>/dev/null" % wicimg)
  333. # parse parted output which looks like this:
  334. # BYT;\n
  335. # /var/tmp/wic/build/tmpfwvjjkf_-201611101222-hda.direct:200MiB:file:512:512:msdos::;\n
  336. # 1:0.00MiB:200MiB:200MiB:ext4::;\n
  337. partlns = res.output.splitlines()[2:]
  338. self.assertEqual(3, len(partlns))
  339. for part in [1, 2, 3]:
  340. part_file = os.path.join(self.resultdir, "selftest_img.part%d" % part)
  341. partln = partlns[part-1].split(":")
  342. self.assertEqual(7, len(partln))
  343. start = int(partln[1].rstrip("B")) / 512
  344. length = int(partln[3].rstrip("B")) / 512
  345. runCmd("dd if=%s of=%s skip=%d count=%d" %
  346. (wicimg, part_file, start, length))
  347. def extract_files(debugfs_output):
  348. """
  349. extract file names from the output of debugfs -R 'ls -p',
  350. which looks like this:
  351. /2/040755/0/0/.//\n
  352. /2/040755/0/0/..//\n
  353. /11/040700/0/0/lost+found^M//\n
  354. /12/040755/1002/1002/run//\n
  355. /13/040755/1002/1002/sys//\n
  356. /14/040755/1002/1002/bin//\n
  357. /80/040755/1002/1002/var//\n
  358. /92/040755/1002/1002/tmp//\n
  359. """
  360. # NOTE the occasional ^M in file names
  361. return [line.split('/')[5].strip() for line in \
  362. debugfs_output.strip().split('/\n')]
  363. # Test partition 1, should contain the normal root directories, except
  364. # /usr.
  365. res = runCmd("debugfs -R 'ls -p' %s 2>/dev/null" % \
  366. os.path.join(self.resultdir, "selftest_img.part1"))
  367. files = extract_files(res.output)
  368. self.assertIn("etc", files)
  369. self.assertNotIn("usr", files)
  370. # Partition 2, should contain common directories for /usr, not root
  371. # directories.
  372. res = runCmd("debugfs -R 'ls -p' %s 2>/dev/null" % \
  373. os.path.join(self.resultdir, "selftest_img.part2"))
  374. files = extract_files(res.output)
  375. self.assertNotIn("etc", files)
  376. self.assertNotIn("usr", files)
  377. self.assertIn("share", files)
  378. # Partition 3, should contain the same as partition 2, including the bin
  379. # directory, but not the files inside it.
  380. res = runCmd("debugfs -R 'ls -p' %s 2>/dev/null" % \
  381. os.path.join(self.resultdir, "selftest_img.part3"))
  382. files = extract_files(res.output)
  383. self.assertNotIn("etc", files)
  384. self.assertNotIn("usr", files)
  385. self.assertIn("share", files)
  386. self.assertIn("bin", files)
  387. res = runCmd("debugfs -R 'ls -p bin' %s 2>/dev/null" % \
  388. os.path.join(self.resultdir, "selftest_img.part3"))
  389. files = extract_files(res.output)
  390. self.assertIn(".", files)
  391. self.assertIn("..", files)
  392. self.assertEqual(2, len(files))
  393. for part in [1, 2, 3]:
  394. part_file = os.path.join(self.resultdir, "selftest_img.part%d" % part)
  395. os.remove(part_file)
  396. finally:
  397. os.environ['PATH'] = oldpath
  398. def test_exclude_path_errors(self):
  399. """Test --exclude-path wks option error handling."""
  400. wks_file = 'temp.wks'
  401. # Absolute argument.
  402. with open(wks_file, 'w') as wks:
  403. wks.write("part / --source rootfs --ondisk mmcblk0 --fstype=ext4 --exclude-path /usr")
  404. self.assertNotEqual(0, runCmd("wic create %s -e core-image-minimal -o %s" \
  405. % (wks_file, self.resultdir), ignore_status=True).status)
  406. os.remove(wks_file)
  407. # Argument pointing to parent directory.
  408. with open(wks_file, 'w') as wks:
  409. wks.write("part / --source rootfs --ondisk mmcblk0 --fstype=ext4 --exclude-path ././..")
  410. self.assertNotEqual(0, runCmd("wic create %s -e core-image-minimal -o %s" \
  411. % (wks_file, self.resultdir), ignore_status=True).status)
  412. os.remove(wks_file)
  413. class Wic2(WicTestCase):
  414. def test_bmap_short(self):
  415. """Test generation of .bmap file -m option"""
  416. cmd = "wic create wictestdisk -e core-image-minimal -m -o %s" % self.resultdir
  417. runCmd(cmd)
  418. self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*direct")))
  419. self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*direct.bmap")))
  420. def test_bmap_long(self):
  421. """Test generation of .bmap file --bmap option"""
  422. cmd = "wic create wictestdisk -e core-image-minimal --bmap -o %s" % self.resultdir
  423. runCmd(cmd)
  424. self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*direct")))
  425. self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*direct.bmap")))
  426. def test_image_env(self):
  427. """Test generation of <image>.env files."""
  428. image = 'core-image-minimal'
  429. imgdatadir = self._get_image_env_path(image)
  430. bb_vars = get_bb_vars(['IMAGE_BASENAME', 'WICVARS'], image)
  431. basename = bb_vars['IMAGE_BASENAME']
  432. self.assertEqual(basename, image)
  433. path = os.path.join(imgdatadir, basename) + '.env'
  434. self.assertTrue(os.path.isfile(path))
  435. wicvars = set(bb_vars['WICVARS'].split())
  436. # filter out optional variables
  437. wicvars = wicvars.difference(('DEPLOY_DIR_IMAGE', 'IMAGE_BOOT_FILES',
  438. 'INITRD', 'INITRD_LIVE', 'ISODIR'))
  439. with open(path) as envfile:
  440. content = dict(line.split("=", 1) for line in envfile)
  441. # test if variables used by wic present in the .env file
  442. for var in wicvars:
  443. self.assertTrue(var in content, "%s is not in .env file" % var)
  444. self.assertTrue(content[var])
  445. def test_image_vars_dir_short(self):
  446. """Test image vars directory selection -v option"""
  447. image = 'core-image-minimal'
  448. imgenvdir = self._get_image_env_path(image)
  449. native_sysroot = get_bb_var("RECIPE_SYSROOT_NATIVE", "wic-tools")
  450. runCmd("wic create wictestdisk "
  451. "--image-name=%s -v %s -n %s -o %s"
  452. % (image, imgenvdir, native_sysroot,
  453. self.resultdir))
  454. self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*direct")))
  455. def test_image_vars_dir_long(self):
  456. """Test image vars directory selection --vars option"""
  457. image = 'core-image-minimal'
  458. imgenvdir = self._get_image_env_path(image)
  459. native_sysroot = get_bb_var("RECIPE_SYSROOT_NATIVE", "wic-tools")
  460. runCmd("wic create wictestdisk "
  461. "--image-name=%s "
  462. "--vars %s "
  463. "--native-sysroot %s "
  464. "--outdir %s"
  465. % (image, imgenvdir, native_sysroot,
  466. self.resultdir))
  467. self.assertEqual(1, len(glob(self.resultdir + "wictestdisk-*direct")))
  468. @only_for_arch(['i586', 'i686', 'x86_64'])
  469. def test_wic_image_type(self):
  470. """Test building wic images by bitbake"""
  471. config = 'IMAGE_FSTYPES += "wic"\nWKS_FILE = "wic-image-minimal"\n'\
  472. 'MACHINE_FEATURES_append = " efi"\n'
  473. self.append_config(config)
  474. self.assertEqual(0, bitbake('wic-image-minimal').status)
  475. self.remove_config(config)
  476. bb_vars = get_bb_vars(['DEPLOY_DIR_IMAGE', 'MACHINE'])
  477. deploy_dir = bb_vars['DEPLOY_DIR_IMAGE']
  478. machine = bb_vars['MACHINE']
  479. prefix = os.path.join(deploy_dir, 'wic-image-minimal-%s.' % machine)
  480. # check if we have result image and manifests symlinks
  481. # pointing to existing files
  482. for suffix in ('wic', 'manifest'):
  483. path = prefix + suffix
  484. self.assertTrue(os.path.islink(path))
  485. self.assertTrue(os.path.isfile(os.path.realpath(path)))
  486. @only_for_arch(['i586', 'i686', 'x86_64'])
  487. def test_qemu(self):
  488. """Test wic-image-minimal under qemu"""
  489. config = 'IMAGE_FSTYPES += "wic"\nWKS_FILE = "wic-image-minimal"\n'\
  490. 'MACHINE_FEATURES_append = " efi"\n'
  491. self.append_config(config)
  492. self.assertEqual(0, bitbake('wic-image-minimal').status)
  493. self.remove_config(config)
  494. with runqemu('wic-image-minimal', ssh=False) as qemu:
  495. cmd = "mount | grep '^/dev/' | cut -f1,3 -d ' ' | egrep -c -e '/dev/sda1 /boot' " \
  496. "-e '/dev/root /|/dev/sda2 /' -e '/dev/sda3 /media' -e '/dev/sda4 /mnt'"
  497. status, output = qemu.run_serial(cmd)
  498. self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output))
  499. self.assertEqual(output, '4')
  500. cmd = "grep UUID= /etc/fstab"
  501. status, output = qemu.run_serial(cmd)
  502. self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output))
  503. self.assertEqual(output, 'UUID=2c71ef06-a81d-4735-9d3a-379b69c6bdba\t/media\text4\tdefaults\t0\t0')
  504. @only_for_arch(['i586', 'i686', 'x86_64'])
  505. def test_qemu_efi(self):
  506. """Test core-image-minimal efi image under qemu"""
  507. config = 'IMAGE_FSTYPES = "wic"\nWKS_FILE = "mkefidisk.wks"\n'
  508. self.append_config(config)
  509. self.assertEqual(0, bitbake('core-image-minimal ovmf').status)
  510. self.remove_config(config)
  511. with runqemu('core-image-minimal', ssh=False,
  512. runqemuparams='ovmf', image_fstype='wic') as qemu:
  513. cmd = "grep sda. /proc/partitions |wc -l"
  514. status, output = qemu.run_serial(cmd)
  515. self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output))
  516. self.assertEqual(output, '3')
  517. @staticmethod
  518. def _make_fixed_size_wks(size):
  519. """
  520. Create a wks of an image with a single partition. Size of the partition is set
  521. using --fixed-size flag. Returns a tuple: (path to wks file, wks image name)
  522. """
  523. with NamedTemporaryFile("w", suffix=".wks", delete=False) as tempf:
  524. wkspath = tempf.name
  525. tempf.write("part " \
  526. "--source rootfs --ondisk hda --align 4 --fixed-size %d "
  527. "--fstype=ext4\n" % size)
  528. wksname = os.path.splitext(os.path.basename(wkspath))[0]
  529. return wkspath, wksname
  530. def test_fixed_size(self):
  531. """
  532. Test creation of a simple image with partition size controlled through
  533. --fixed-size flag
  534. """
  535. wkspath, wksname = Wic2._make_fixed_size_wks(200)
  536. runCmd("wic create %s -e core-image-minimal -o %s" \
  537. % (wkspath, self.resultdir))
  538. os.remove(wkspath)
  539. wicout = glob(self.resultdir + "%s-*direct" % wksname)
  540. self.assertEqual(1, len(wicout))
  541. wicimg = wicout[0]
  542. native_sysroot = get_bb_var("RECIPE_SYSROOT_NATIVE", "wic-tools")
  543. # verify partition size with wic
  544. res = runCmd("parted -m %s unit mib p 2>/dev/null" % wicimg,
  545. native_sysroot=native_sysroot)
  546. # parse parted output which looks like this:
  547. # BYT;\n
  548. # /var/tmp/wic/build/tmpfwvjjkf_-201611101222-hda.direct:200MiB:file:512:512:msdos::;\n
  549. # 1:0.00MiB:200MiB:200MiB:ext4::;\n
  550. partlns = res.output.splitlines()[2:]
  551. self.assertEqual(1, len(partlns))
  552. self.assertEqual("1:0.00MiB:200MiB:200MiB:ext4::;", partlns[0])
  553. def test_fixed_size_error(self):
  554. """
  555. Test creation of a simple image with partition size controlled through
  556. --fixed-size flag. The size of partition is intentionally set to 1MiB
  557. in order to trigger an error in wic.
  558. """
  559. wkspath, wksname = Wic2._make_fixed_size_wks(1)
  560. self.assertEqual(1, runCmd("wic create %s -e core-image-minimal -o %s" \
  561. % (wkspath, self.resultdir), ignore_status=True).status)
  562. os.remove(wkspath)
  563. wicout = glob(self.resultdir + "%s-*direct" % wksname)
  564. self.assertEqual(0, len(wicout))
  565. @only_for_arch(['i586', 'i686', 'x86_64'])
  566. def test_rawcopy_plugin_qemu(self):
  567. """Test rawcopy plugin in qemu"""
  568. # build ext4 and wic images
  569. for fstype in ("ext4", "wic"):
  570. config = 'IMAGE_FSTYPES = "%s"\nWKS_FILE = "test_rawcopy_plugin.wks.in"\n' % fstype
  571. self.append_config(config)
  572. self.assertEqual(0, bitbake('core-image-minimal').status)
  573. self.remove_config(config)
  574. with runqemu('core-image-minimal', ssh=False, image_fstype='wic') as qemu:
  575. cmd = "grep sda. /proc/partitions |wc -l"
  576. status, output = qemu.run_serial(cmd)
  577. self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output))
  578. self.assertEqual(output, '2')
  579. def test_rawcopy_plugin(self):
  580. """Test rawcopy plugin"""
  581. img = 'core-image-minimal'
  582. machine = get_bb_var('MACHINE', img)
  583. with NamedTemporaryFile("w", suffix=".wks") as wks:
  584. wks.writelines(['part /boot --active --source bootimg-pcbios\n',
  585. 'part / --source rawcopy --sourceparams="file=%s-%s.ext4" --use-uuid\n'\
  586. % (img, machine),
  587. 'bootloader --timeout=0 --append="console=ttyS0,115200n8"\n'])
  588. wks.flush()
  589. cmd = "wic create %s -e %s -o %s" % (wks.name, img, self.resultdir)
  590. runCmd(cmd)
  591. wksname = os.path.splitext(os.path.basename(wks.name))[0]
  592. out = glob(self.resultdir + "%s-*direct" % wksname)
  593. self.assertEqual(1, len(out))
  594. def test_fs_types(self):
  595. """Test filesystem types for empty and not empty partitions"""
  596. img = 'core-image-minimal'
  597. with NamedTemporaryFile("w", suffix=".wks") as wks:
  598. wks.writelines(['part ext2 --fstype ext2 --source rootfs\n',
  599. 'part btrfs --fstype btrfs --source rootfs --size 40M\n',
  600. 'part squash --fstype squashfs --source rootfs\n',
  601. 'part swap --fstype swap --size 1M\n',
  602. 'part emptyvfat --fstype vfat --size 1M\n',
  603. 'part emptymsdos --fstype msdos --size 1M\n',
  604. 'part emptyext2 --fstype ext2 --size 1M\n',
  605. 'part emptybtrfs --fstype btrfs --size 150M\n'])
  606. wks.flush()
  607. cmd = "wic create %s -e %s -o %s" % (wks.name, img, self.resultdir)
  608. runCmd(cmd)
  609. wksname = os.path.splitext(os.path.basename(wks.name))[0]
  610. out = glob(self.resultdir + "%s-*direct" % wksname)
  611. self.assertEqual(1, len(out))
  612. def test_kickstart_parser(self):
  613. """Test wks parser options"""
  614. with NamedTemporaryFile("w", suffix=".wks") as wks:
  615. wks.writelines(['part / --fstype ext3 --source rootfs --system-id 0xFF '\
  616. '--overhead-factor 1.2 --size 100k\n'])
  617. wks.flush()
  618. cmd = "wic create %s -e core-image-minimal -o %s" % (wks.name, self.resultdir)
  619. runCmd(cmd)
  620. wksname = os.path.splitext(os.path.basename(wks.name))[0]
  621. out = glob(self.resultdir + "%s-*direct" % wksname)
  622. self.assertEqual(1, len(out))
  623. def test_image_bootpart_globbed(self):
  624. """Test globbed sources with image-bootpart plugin"""
  625. img = "core-image-minimal"
  626. cmd = "wic create sdimage-bootpart -e %s -o %s" % (img, self.resultdir)
  627. config = 'IMAGE_BOOT_FILES = "%s*"' % get_bb_var('KERNEL_IMAGETYPE', img)
  628. self.append_config(config)
  629. runCmd(cmd)
  630. self.remove_config(config)
  631. self.assertEqual(1, len(glob(self.resultdir + "sdimage-bootpart-*direct")))
  632. def test_sparse_copy(self):
  633. """Test sparse_copy with FIEMAP and SEEK_HOLE filemap APIs"""
  634. libpath = os.path.join(get_bb_var('COREBASE'), 'scripts', 'lib', 'wic')
  635. sys.path.insert(0, libpath)
  636. from filemap import FilemapFiemap, FilemapSeek, sparse_copy, ErrorNotSupp
  637. with NamedTemporaryFile("w", suffix=".wic-sparse") as sparse:
  638. src_name = sparse.name
  639. src_size = 1024 * 10
  640. sparse.truncate(src_size)
  641. # write one byte to the file
  642. with open(src_name, 'r+b') as sfile:
  643. sfile.seek(1024 * 4)
  644. sfile.write(b'\x00')
  645. dest = sparse.name + '.out'
  646. # copy src file to dest using different filemap APIs
  647. for api in (FilemapFiemap, FilemapSeek, None):
  648. if os.path.exists(dest):
  649. os.unlink(dest)
  650. try:
  651. sparse_copy(sparse.name, dest, api=api)
  652. except ErrorNotSupp:
  653. continue # skip unsupported API
  654. dest_stat = os.stat(dest)
  655. self.assertEqual(dest_stat.st_size, src_size)
  656. # 8 blocks is 4K (physical sector size)
  657. self.assertEqual(dest_stat.st_blocks, 8)
  658. os.unlink(dest)
  659. def test_wic_ls(self):
  660. """Test listing image content using 'wic ls'"""
  661. runCmd("wic create wictestdisk "
  662. "--image-name=core-image-minimal "
  663. "-D -o %s" % self.resultdir)
  664. images = glob(self.resultdir + "wictestdisk-*.direct")
  665. self.assertEqual(1, len(images))
  666. sysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'wic-tools')
  667. # list partitions
  668. result = runCmd("wic ls %s -n %s" % (images[0], sysroot))
  669. self.assertEqual(3, len(result.output.split('\n')))
  670. # list directory content of the first partition
  671. result = runCmd("wic ls %s:1/ -n %s" % (images[0], sysroot))
  672. self.assertEqual(6, len(result.output.split('\n')))
  673. def test_wic_cp(self):
  674. """Test copy files and directories to the the wic image."""
  675. runCmd("wic create wictestdisk "
  676. "--image-name=core-image-minimal "
  677. "-D -o %s" % self.resultdir)
  678. images = glob(self.resultdir + "wictestdisk-*.direct")
  679. self.assertEqual(1, len(images))
  680. sysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'wic-tools')
  681. # list directory content of the first partition
  682. result = runCmd("wic ls %s:1/ -n %s" % (images[0], sysroot))
  683. self.assertEqual(6, len(result.output.split('\n')))
  684. with NamedTemporaryFile("w", suffix=".wic-cp") as testfile:
  685. testfile.write("test")
  686. # copy file to the partition
  687. runCmd("wic cp %s %s:1/ -n %s" % (testfile.name, images[0], sysroot))
  688. # check if file is there
  689. result = runCmd("wic ls %s:1/ -n %s" % (images[0], sysroot))
  690. self.assertEqual(7, len(result.output.split('\n')))
  691. self.assertTrue(os.path.basename(testfile.name) in result.output)
  692. # prepare directory
  693. testdir = os.path.join(self.resultdir, 'wic-test-cp-dir')
  694. testsubdir = os.path.join(testdir, 'subdir')
  695. os.makedirs(os.path.join(testsubdir))
  696. copy(testfile.name, testdir)
  697. # copy directory to the partition
  698. runCmd("wic cp %s %s:1/ -n %s" % (testdir, images[0], sysroot))
  699. # check if directory is there
  700. result = runCmd("wic ls %s:1/ -n %s" % (images[0], sysroot))
  701. self.assertEqual(8, len(result.output.split('\n')))
  702. self.assertTrue(os.path.basename(testdir) in result.output)
  703. def test_wic_rm(self):
  704. """Test removing files and directories from the the wic image."""
  705. runCmd("wic create mkefidisk "
  706. "--image-name=core-image-minimal "
  707. "-D -o %s" % self.resultdir)
  708. images = glob(self.resultdir + "mkefidisk-*.direct")
  709. self.assertEqual(1, len(images))
  710. sysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'wic-tools')
  711. # list directory content of the first partition
  712. result = runCmd("wic ls %s:1 -n %s" % (images[0], sysroot))
  713. self.assertIn('\nBZIMAGE ', result.output)
  714. self.assertIn('\nEFI <DIR> ', result.output)
  715. # remove file
  716. runCmd("wic rm %s:1/bzimage -n %s" % (images[0], sysroot))
  717. # remove directory
  718. runCmd("wic rm %s:1/efi -n %s" % (images[0], sysroot))
  719. # check if they're removed
  720. result = runCmd("wic ls %s:1 -n %s" % (images[0], sysroot))
  721. self.assertNotIn('\nBZIMAGE ', result.output)
  722. self.assertNotIn('\nEFI <DIR> ', result.output)
  723. def test_mkfs_extraopts(self):
  724. """Test wks option --mkfs-extraopts for empty and not empty partitions"""
  725. img = 'core-image-minimal'
  726. with NamedTemporaryFile("w", suffix=".wks") as wks:
  727. wks.writelines(
  728. ['part ext2 --fstype ext2 --source rootfs --mkfs-extraopts "-D -F -i 8192"\n',
  729. "part btrfs --fstype btrfs --source rootfs --size 40M --mkfs-extraopts='--quiet'\n",
  730. 'part squash --fstype squashfs --source rootfs --mkfs-extraopts "-no-sparse -b 4096"\n',
  731. 'part emptyvfat --fstype vfat --size 1M --mkfs-extraopts "-S 1024 -s 64"\n',
  732. 'part emptymsdos --fstype msdos --size 1M --mkfs-extraopts "-S 1024 -s 64"\n',
  733. 'part emptyext2 --fstype ext2 --size 1M --mkfs-extraopts "-D -F -i 8192"\n',
  734. 'part emptybtrfs --fstype btrfs --size 100M --mkfs-extraopts "--mixed -K"\n'])
  735. wks.flush()
  736. cmd = "wic create %s -e %s -o %s" % (wks.name, img, self.resultdir)
  737. runCmd(cmd)
  738. wksname = os.path.splitext(os.path.basename(wks.name))[0]
  739. out = glob(self.resultdir + "%s-*direct" % wksname)
  740. self.assertEqual(1, len(out))
  741. def test_expand_mbr_image(self):
  742. """Test wic write --expand command for mbr image"""
  743. # build an image
  744. config = 'IMAGE_FSTYPES = "wic"\nWKS_FILE = "directdisk.wks"\n'
  745. self.append_config(config)
  746. self.assertEqual(0, bitbake('core-image-minimal').status)
  747. # get path to the image
  748. bb_vars = get_bb_vars(['DEPLOY_DIR_IMAGE', 'MACHINE'])
  749. deploy_dir = bb_vars['DEPLOY_DIR_IMAGE']
  750. machine = bb_vars['MACHINE']
  751. image_path = os.path.join(deploy_dir, 'core-image-minimal-%s.wic' % machine)
  752. self.remove_config(config)
  753. try:
  754. # expand image to 1G
  755. new_image_path = None
  756. with NamedTemporaryFile(mode='wb', suffix='.wic.exp',
  757. dir=deploy_dir, delete=False) as sparse:
  758. sparse.truncate(1024 ** 3)
  759. new_image_path = sparse.name
  760. sysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'wic-tools')
  761. cmd = "wic write -n %s --expand 1:0 %s %s" % (sysroot, image_path, new_image_path)
  762. runCmd(cmd)
  763. # check if partitions are expanded
  764. orig = runCmd("wic ls %s -n %s" % (image_path, sysroot))
  765. exp = runCmd("wic ls %s -n %s" % (new_image_path, sysroot))
  766. orig_sizes = [int(line.split()[3]) for line in orig.output.split('\n')[1:]]
  767. exp_sizes = [int(line.split()[3]) for line in exp.output.split('\n')[1:]]
  768. self.assertEqual(orig_sizes[0], exp_sizes[0]) # first partition is not resized
  769. self.assertTrue(orig_sizes[1] < exp_sizes[1])
  770. # Check if all free space is partitioned
  771. result = runCmd("%s/usr/sbin/sfdisk -F %s" % (sysroot, new_image_path))
  772. self.assertTrue("0 B, 0 bytes, 0 sectors" in result.output)
  773. os.rename(image_path, image_path + '.bak')
  774. os.rename(new_image_path, image_path)
  775. # Check if it boots in qemu
  776. with runqemu('core-image-minimal', ssh=False) as qemu:
  777. cmd = "ls /etc/"
  778. status, output = qemu.run_serial('true')
  779. self.assertEqual(1, status, 'Failed to run command "%s": %s' % (cmd, output))
  780. finally:
  781. if os.path.exists(new_image_path):
  782. os.unlink(new_image_path)
  783. if os.path.exists(image_path + '.bak'):
  784. os.rename(image_path + '.bak', image_path)
  785. def test_wic_ls_ext(self):
  786. """Test listing content of the ext partition using 'wic ls'"""
  787. runCmd("wic create wictestdisk "
  788. "--image-name=core-image-minimal "
  789. "-D -o %s" % self.resultdir)
  790. images = glob(self.resultdir + "wictestdisk-*.direct")
  791. self.assertEqual(1, len(images))
  792. sysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'wic-tools')
  793. # list directory content of the second ext4 partition
  794. result = runCmd("wic ls %s:2/ -n %s" % (images[0], sysroot))
  795. self.assertTrue(set(['bin', 'home', 'proc', 'usr', 'var', 'dev', 'lib', 'sbin']).issubset(
  796. set(line.split()[-1] for line in result.output.split('\n') if line)))
  797. def test_wic_cp_ext(self):
  798. """Test copy files and directories to the ext partition."""
  799. runCmd("wic create wictestdisk "
  800. "--image-name=core-image-minimal "
  801. "-D -o %s" % self.resultdir)
  802. images = glob(self.resultdir + "wictestdisk-*.direct")
  803. self.assertEqual(1, len(images))
  804. sysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'wic-tools')
  805. # list directory content of the ext4 partition
  806. result = runCmd("wic ls %s:2/ -n %s" % (images[0], sysroot))
  807. dirs = set(line.split()[-1] for line in result.output.split('\n') if line)
  808. self.assertTrue(set(['bin', 'home', 'proc', 'usr', 'var', 'dev', 'lib', 'sbin']).issubset(dirs))
  809. with NamedTemporaryFile("w", suffix=".wic-cp") as testfile:
  810. testfile.write("test")
  811. # copy file to the partition
  812. runCmd("wic cp %s %s:2/ -n %s" % (testfile.name, images[0], sysroot))
  813. # check if file is there
  814. result = runCmd("wic ls %s:2/ -n %s" % (images[0], sysroot))
  815. newdirs = set(line.split()[-1] for line in result.output.split('\n') if line)
  816. self.assertEqual(newdirs.difference(dirs), set([os.path.basename(testfile.name)]))
  817. def test_wic_rm_ext(self):
  818. """Test removing files from the ext partition."""
  819. runCmd("wic create mkefidisk "
  820. "--image-name=core-image-minimal "
  821. "-D -o %s" % self.resultdir)
  822. images = glob(self.resultdir + "mkefidisk-*.direct")
  823. self.assertEqual(1, len(images))
  824. sysroot = get_bb_var('RECIPE_SYSROOT_NATIVE', 'wic-tools')
  825. # list directory content of the /etc directory on ext4 partition
  826. result = runCmd("wic ls %s:2/etc/ -n %s" % (images[0], sysroot))
  827. self.assertTrue('fstab' in [line.split()[-1] for line in result.output.split('\n') if line])
  828. # remove file
  829. runCmd("wic rm %s:2/etc/fstab -n %s" % (images[0], sysroot))
  830. # check if it's removed
  831. result = runCmd("wic ls %s:2/etc/ -n %s" % (images[0], sysroot))
  832. self.assertTrue('fstab' not in [line.split()[-1] for line in result.output.split('\n') if line])