qvm_create.py 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. # -*- encoding: utf8 -*-
  2. #
  3. # The Qubes OS Project, http://www.qubes-os.org
  4. #
  5. # Copyright (C) 2017 Marek Marczykowski-Górecki
  6. # <marmarek@invisiblethingslab.com>
  7. #
  8. # This program is free software; you can redistribute it and/or modify
  9. # it under the terms of the GNU Lesser General Public License as published by
  10. # the Free Software Foundation; either version 2.1 of the License, or
  11. # (at your option) any later version.
  12. #
  13. # This program is distributed in the hope that it will be useful,
  14. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. # GNU Lesser General Public License for more details.
  17. #
  18. # You should have received a copy of the GNU Lesser General Public License along
  19. # with this program; if not, see <http://www.gnu.org/licenses/>.
  20. import os
  21. import tempfile
  22. import qubesadmin.tests
  23. import qubesadmin.tests.tools
  24. import qubesadmin.tools.qvm_create
  25. class TC_00_qvm_create(qubesadmin.tests.QubesTestCase):
  26. def test_000_just_appvm(self):
  27. self.app.expected_calls[('dom0', 'admin.vm.Create.AppVM', None,
  28. b'name=new-vm label=red')] = b'0\x00'
  29. self.app.expected_calls[('dom0', 'admin.label.List', None, None)] = \
  30. b'0\x00red\nblue\n'
  31. self.app.expected_calls[('dom0', 'admin.vm.List', None, None)] = \
  32. b'0\x00new-vm class=AppVM state=Halted\n'
  33. qubesadmin.tools.qvm_create.main(['-l', 'red', 'new-vm'], app=self.app)
  34. self.assertAllCalled()
  35. def test_001_missing_vm(self):
  36. with self.assertRaises(SystemExit):
  37. with qubesadmin.tests.tools.StderrBuffer() as stderr:
  38. qubesadmin.tools.qvm_create.main(['-l', 'red'], app=self.app)
  39. self.assertIn('NAME', stderr.getvalue())
  40. self.assertAllCalled()
  41. def test_002_custom_template(self):
  42. self.app.expected_calls[('dom0', 'admin.vm.Create.AppVM',
  43. 'some-template', b'name=new-vm label=red')] = b'0\x00'
  44. self.app.expected_calls[('dom0', 'admin.label.List', None, None)] = \
  45. b'0\x00red\nblue\n'
  46. self.app.expected_calls[('dom0', 'admin.vm.List', None, None)] = \
  47. b'0\x00new-vm class=AppVM state=Halted\n'
  48. qubesadmin.tools.qvm_create.main(['-l', 'red', '-t',
  49. 'some-template', 'new-vm'], app=self.app)
  50. self.assertAllCalled()
  51. def test_003_properties(self):
  52. self.app.expected_calls[('dom0', 'admin.vm.Create.AppVM',
  53. None, b'name=new-vm label=red')] = b'0\x00'
  54. self.app.expected_calls[('dom0', 'admin.label.List', None, None)] = \
  55. b'0\x00red\nblue\n'
  56. self.app.expected_calls[('dom0', 'admin.vm.List', None, None)] = \
  57. b'0\x00new-vm class=AppVM state=Halted\n'
  58. self.app.expected_calls[('new-vm', 'admin.vm.property.Set',
  59. 'netvm', b'sys-whonix')] = b'0\x00'
  60. qubesadmin.tools.qvm_create.main(['-l', 'red', '--prop',
  61. 'netvm=sys-whonix', 'new-vm'],
  62. app=self.app)
  63. self.assertAllCalled()
  64. def test_004_pool(self):
  65. self.app.expected_calls[('dom0', 'admin.vm.CreateInPool.AppVM',
  66. None, b'name=new-vm label=red pool=some-pool')] = b'0\x00'
  67. self.app.expected_calls[('dom0', 'admin.label.List', None, None)] = \
  68. b'0\x00red\nblue\n'
  69. self.app.expected_calls[('dom0', 'admin.vm.List', None, None)] = \
  70. b'0\x00new-vm class=AppVM state=Halted\n'
  71. qubesadmin.tools.qvm_create.main(['-l', 'red', '-P', 'some-pool',
  72. 'new-vm'],
  73. app=self.app)
  74. self.assertAllCalled()
  75. def test_005_pools(self):
  76. self.app.expected_calls[('dom0', 'admin.vm.CreateInPool.AppVM',
  77. None, b'name=new-vm label=red pool:private=some-pool '
  78. b'pool:volatile=other-pool')] = b'0\x00'
  79. self.app.expected_calls[('dom0', 'admin.label.List', None, None)] = \
  80. b'0\x00red\nblue\n'
  81. self.app.expected_calls[('dom0', 'admin.vm.List', None, None)] = \
  82. b'0\x00new-vm class=AppVM state=Halted\n'
  83. qubesadmin.tools.qvm_create.main(['-l', 'red', '--pool',
  84. 'private=some-pool', '--pool', 'volatile=other-pool', 'new-vm'],
  85. app=self.app)
  86. self.assertAllCalled()
  87. def test_005_root_copy_from(self):
  88. with tempfile.NamedTemporaryFile() as root_file:
  89. root_file.file.write(b'root data')
  90. root_file.file.flush()
  91. self.app.expected_calls[('dom0', 'admin.vm.Create.AppVM',
  92. None, b'name=new-vm label=red')] = b'0\x00'
  93. self.app.expected_calls[('dom0', 'admin.label.List', None, None)] = \
  94. b'0\x00red\nblue\n'
  95. self.app.expected_calls[('dom0', 'admin.vm.List', None, None)] = \
  96. b'0\x00new-vm class=AppVM state=Halted\n'
  97. self.app.expected_calls[
  98. ('new-vm', 'admin.vm.volume.List', None, None)] = \
  99. b'0\x00root\nprivate\nvolatile\nkernel\n'
  100. self.app.expected_calls[
  101. ('new-vm', 'admin.vm.volume.Info', 'root', None)] = \
  102. b'0\x00' \
  103. b'pool=other-pool\n' \
  104. b'vid=new-vm-root\n' \
  105. b'size=10000000\n'
  106. self.app.expected_calls[
  107. ('new-vm', 'admin.vm.volume.Import', 'root', b'root data')] = \
  108. b'0\0'
  109. qubesadmin.tools.qvm_create.main(['-l', 'red',
  110. '--root-copy-from=' + root_file.name, 'new-vm'],
  111. app=self.app)
  112. self.assertAllCalled()
  113. self.assertTrue(os.path.exists(root_file.name))
  114. def test_006_root_move_from(self):
  115. with tempfile.NamedTemporaryFile(delete=False) as root_file:
  116. root_file.file.write(b'root data')
  117. root_file.file.flush()
  118. self.app.expected_calls[('dom0', 'admin.vm.Create.AppVM',
  119. None, b'name=new-vm label=red')] = b'0\x00'
  120. self.app.expected_calls[('dom0', 'admin.label.List', None, None)] = \
  121. b'0\x00red\nblue\n'
  122. self.app.expected_calls[('dom0', 'admin.vm.List', None, None)] = \
  123. b'0\x00new-vm class=AppVM state=Halted\n'
  124. self.app.expected_calls[
  125. ('new-vm', 'admin.vm.volume.List', None, None)] = \
  126. b'0\x00root\nprivate\nvolatile\nkernel\n'
  127. self.app.expected_calls[
  128. ('new-vm', 'admin.vm.volume.Info', 'root', None)] = \
  129. b'0\x00' \
  130. b'pool=other-pool\n' \
  131. b'vid=new-vm-root\n' \
  132. b'size=20000000\n'
  133. self.app.expected_calls[
  134. ('new-vm', 'admin.vm.volume.Import', 'root', b'root data')] = \
  135. b'0\0'
  136. qubesadmin.tools.qvm_create.main(['-l', 'red',
  137. '--root-move-from=' + root_file.name, 'new-vm'],
  138. app=self.app)
  139. self.assertAllCalled()
  140. self.assertFalse(os.path.exists(root_file.name))
  141. def test_007_root_move_copy_both(self):
  142. with tempfile.NamedTemporaryFile() as root_file:
  143. root_file.file.write(b'root data')
  144. root_file.file.flush()
  145. with self.assertRaises(SystemExit):
  146. qubesadmin.tools.qvm_create.main(['-l', 'red',
  147. '--root-copy-from=' + root_file.name,
  148. '--root-move-from=' + root_file.name,
  149. 'new-vm'],
  150. app=self.app)
  151. self.assertAllCalled()
  152. self.assertTrue(os.path.exists(root_file.name))
  153. def test_008_root_invalid_path(self):
  154. with self.assertRaises(SystemExit):
  155. qubesadmin.tools.qvm_create.main(['-l', 'red',
  156. '--root-copy-from=/invalid', 'new-vm'],
  157. app=self.app)
  158. self.assertAllCalled()
  159. def test_009_help_classes(self):
  160. self.app.expected_calls[('dom0', 'admin.vmclass.List',
  161. None, None)] = b'0\x00StandaloneVM\nAppVM\nTemplateVM\nDispVM\n'
  162. with qubesadmin.tests.tools.StdoutBuffer() as stdout:
  163. qubesadmin.tools.qvm_create.main(['--help-classes'],
  164. app=self.app)
  165. self.assertEqual(stdout.getvalue(),
  166. 'AppVM\nDispVM\nStandaloneVM\nTemplateVM\n')
  167. self.assertAllCalled()
  168. def test_010_root_copy_from_with_resize(self):
  169. with tempfile.NamedTemporaryFile() as root_file:
  170. root_file.file.write(b'root data')
  171. root_file.file.flush()
  172. self.app.expected_calls[('dom0', 'admin.vm.Create.AppVM',
  173. None, b'name=new-vm label=red')] = b'0\x00'
  174. self.app.expected_calls[('dom0', 'admin.label.List', None, None)] = \
  175. b'0\x00red\nblue\n'
  176. self.app.expected_calls[('dom0', 'admin.vm.List', None, None)] = \
  177. b'0\x00new-vm class=AppVM state=Halted\n'
  178. self.app.expected_calls[
  179. ('new-vm', 'admin.vm.volume.List', None, None)] = \
  180. b'0\x00root\nprivate\nvolatile\nkernel\n'
  181. self.app.expected_calls[
  182. ('new-vm', 'admin.vm.volume.Info', 'root', None)] = \
  183. b'0\x00' \
  184. b'pool=other-pool\n' \
  185. b'vid=new-vm-root\n' \
  186. b'size=2\n'
  187. self.app.expected_calls[
  188. ('new-vm', 'admin.vm.volume.Resize', 'root', b'9')] = \
  189. b'0\0'
  190. self.app.expected_calls[
  191. ('new-vm', 'admin.vm.volume.Import', 'root', b'root data')] = \
  192. b'0\0'
  193. qubesadmin.tools.qvm_create.main(['-l', 'red',
  194. '--root-copy-from=' + root_file.name, 'new-vm'],
  195. app=self.app)
  196. self.assertAllCalled()
  197. self.assertTrue(os.path.exists(root_file.name))