pvgrub.py 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*-
  3. #
  4. # The Qubes OS Project, http://www.qubes-os.org
  5. #
  6. # Copyright (C) 2016 Marek Marczykowski-Górecki
  7. # <marmarek@invisiblethingslab.com>
  8. #
  9. # This program is free software; you can redistribute it and/or
  10. # modify it under the terms of the GNU General Public License
  11. # as published by the Free Software Foundation; either version 2
  12. # of the License, or (at your option) any later version.
  13. #
  14. # This program is distributed in the hope that it will be useful,
  15. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. # GNU General Public License for more details.
  18. #
  19. # You should have received a copy of the GNU General Public License
  20. # along with this program; if not, write to the Free Software
  21. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  22. #
  23. #
  24. import os
  25. import unittest
  26. import qubes.tests
  27. @unittest.skipUnless(os.path.exists('/var/lib/qubes/vm-kernels/pvgrub2'),
  28. 'grub-xen package not installed')
  29. class TC_40_PVGrub(qubes.tests.SystemTestsMixin):
  30. def setUp(self):
  31. super(TC_40_PVGrub, self).setUp()
  32. supported = False
  33. if self.template.startswith('fedora-'):
  34. supported = True
  35. elif self.template.startswith('debian-'):
  36. supported = True
  37. if not supported:
  38. self.skipTest("Template {} not supported by this test".format(
  39. self.template))
  40. def install_packages(self, vm):
  41. if self.template.startswith('fedora-'):
  42. cmd_install1 = 'dnf clean expire-cache && ' \
  43. 'dnf install -y qubes-kernel-vm-support grub2-tools'
  44. cmd_install2 = 'dnf install -y kernel && ' \
  45. 'KVER=$(rpm -q --qf %{VERSION}-%{RELEASE}.%{ARCH} kernel) && ' \
  46. 'dnf install --allowerasing -y kernel-devel-$KVER && ' \
  47. 'dkms autoinstall -k $KVER'
  48. cmd_update_grub = 'grub2-mkconfig -o /boot/grub2/grub.cfg'
  49. elif self.template.startswith('debian-'):
  50. cmd_install1 = 'apt-get update && apt-get install -y ' \
  51. 'qubes-kernel-vm-support grub2-common'
  52. cmd_install2 = 'apt-get install -y linux-image-amd64'
  53. cmd_update_grub = 'mkdir /boot/grub && update-grub2'
  54. else:
  55. assert False, "Unsupported template?!"
  56. for cmd in [cmd_install1, cmd_install2, cmd_update_grub]:
  57. p = vm.run(cmd, user="root", passio_popen=True, passio_stderr=True)
  58. (stdout, stderr) = p.communicate()
  59. self.assertEquals(p.returncode, 0,
  60. "Failed command: {}\nSTDOUT: {}\nSTDERR: {}"
  61. .format(cmd, stdout, stderr))
  62. def get_kernel_version(self, vm):
  63. if self.template.startswith('fedora-'):
  64. cmd_get_kernel_version = 'rpm -q kernel|sort -n|tail -1|' \
  65. 'cut -d - -f 2-'
  66. elif self.template.startswith('debian-'):
  67. cmd_get_kernel_version = \
  68. 'dpkg-query --showformat=\'${Package}\\n\' --show ' \
  69. '\'linux-image-*-amd64\'|sort -n|tail -1|cut -d - -f 3-'
  70. else:
  71. raise RuntimeError("Unsupported template?!")
  72. p = vm.run(cmd_get_kernel_version, user="root", passio_popen=True)
  73. (kver, _) = p.communicate()
  74. self.assertEquals(p.returncode, 0,
  75. "Failed command: {}".format(cmd_get_kernel_version))
  76. return kver.strip()
  77. def test_000_standalone_vm(self):
  78. testvm1 = self.qc.add_new_vm("QubesAppVm",
  79. template=None,
  80. name=self.make_vm_name('vm1'))
  81. testvm1.create_on_disk(verbose=False,
  82. source_template=self.qc.get_vm_by_name(
  83. self.template))
  84. self.save_and_reload_db()
  85. self.qc.unlock_db()
  86. testvm1 = self.qc[testvm1.qid]
  87. testvm1.start()
  88. self.install_packages(testvm1)
  89. kver = self.get_kernel_version(testvm1)
  90. self.shutdown_and_wait(testvm1)
  91. self.qc.lock_db_for_writing()
  92. self.qc.load()
  93. testvm1 = self.qc[testvm1.qid]
  94. testvm1.kernel = 'pvgrub2'
  95. self.save_and_reload_db()
  96. self.qc.unlock_db()
  97. testvm1 = self.qc[testvm1.qid]
  98. testvm1.start()
  99. p = testvm1.run('uname -r', passio_popen=True)
  100. (actual_kver, _) = p.communicate()
  101. self.assertEquals(actual_kver.strip(), kver)
  102. def test_010_template_based_vm(self):
  103. test_template = self.qc.add_new_vm("QubesTemplateVm",
  104. template=None,
  105. name=self.make_vm_name('template'))
  106. test_template.clone_attrs(self.qc.get_vm_by_name(self.template))
  107. test_template.clone_disk_files(
  108. src_vm=self.qc.get_vm_by_name(self.template),
  109. verbose=False)
  110. testvm1 = self.qc.add_new_vm("QubesAppVm",
  111. template=test_template,
  112. name=self.make_vm_name('vm1'))
  113. testvm1.create_on_disk(verbose=False,
  114. source_template=test_template)
  115. self.save_and_reload_db()
  116. self.qc.unlock_db()
  117. test_template = self.qc[test_template.qid]
  118. testvm1 = self.qc[testvm1.qid]
  119. test_template.start()
  120. self.install_packages(test_template)
  121. kver = self.get_kernel_version(test_template)
  122. self.shutdown_and_wait(test_template)
  123. self.qc.lock_db_for_writing()
  124. self.qc.load()
  125. test_template = self.qc[test_template.qid]
  126. test_template.kernel = 'pvgrub2'
  127. testvm1 = self.qc[testvm1.qid]
  128. testvm1.kernel = 'pvgrub2'
  129. self.save_and_reload_db()
  130. self.qc.unlock_db()
  131. # Check if TemplateBasedVM boots and has the right kernel
  132. testvm1 = self.qc[testvm1.qid]
  133. testvm1.start()
  134. p = testvm1.run('uname -r', passio_popen=True)
  135. (actual_kver, _) = p.communicate()
  136. self.assertEquals(actual_kver.strip(), kver)
  137. # And the same for the TemplateVM itself
  138. test_template = self.qc[test_template.qid]
  139. test_template.start()
  140. p = test_template.run('uname -r', passio_popen=True)
  141. (actual_kver, _) = p.communicate()
  142. self.assertEquals(actual_kver.strip(), kver)
  143. def load_tests(loader, tests, pattern):
  144. try:
  145. qc = qubes.qubes.QubesVmCollection()
  146. qc.lock_db_for_reading()
  147. qc.load()
  148. qc.unlock_db()
  149. templates = [vm.name for vm in qc.values() if
  150. isinstance(vm, qubes.qubes.QubesTemplateVm)]
  151. except OSError:
  152. templates = []
  153. for template in templates:
  154. tests.addTests(loader.loadTestsFromTestCase(
  155. type(
  156. 'TC_40_PVGrub_' + template,
  157. (TC_40_PVGrub, qubes.tests.QubesTestCase),
  158. {'template': template})))
  159. return tests