backupcompatibility.py 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390
  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*-
  3. #
  4. # The Qubes OS Project, http://www.qubes-os.org
  5. #
  6. # Copyright (C) 2014 Marek Marczykowski-Górecki <marmarek@invisiblethingslab.com>
  7. #
  8. # This program is free software; you can redistribute it and/or
  9. # modify it under the terms of the GNU General Public License
  10. # as published by the Free Software Foundation; either version 2
  11. # of the License, or (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 General Public License for more details.
  17. #
  18. # You should have received a copy of the GNU General Public License
  19. # along with this program; if not, write to the Free Software
  20. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  21. #
  22. #
  23. from multiprocessing import Queue
  24. import os
  25. import shutil
  26. import subprocess
  27. import unittest
  28. import sys
  29. from qubes.qubes import QubesVmCollection, QubesException
  30. from qubes import backup
  31. VM_PREFIX = "test-"
  32. QUBESXML_R2B2 = """
  33. <QubesVmCollection updatevm="3" default_kernel="3.7.6-2" default_netvm="3" default_fw_netvm="2" default_template="1" clockvm="2">
  34. <QubesTemplateVm installed_by_rpm="True" kernel="3.7.6-2" uses_default_kernelopts="True" qid="1" include_in_backups="True" uses_default_kernel="True" qrexec_timeout="60" internal="False" conf_file="fedora-18-x64.conf" label="black" template_qid="none" kernelopts="" memory="400" default_user="user" netvm_qid="3" uses_default_netvm="True" volatile_img="volatile.img" services="{'meminfo-writer': True}" maxmem="1535" pcidevs="[]" name="fedora-18-x64" private_img="private.img" vcpus="2" root_img="root.img" debug="False" dir_path="/var/lib/qubes/vm-templates/fedora-18-x64"/>
  35. <QubesNetVm installed_by_rpm="False" kernel="3.7.6-2" uses_default_kernelopts="True" qid="2" include_in_backups="True" uses_default_kernel="True" qrexec_timeout="60" internal="False" conf_file="netvm.conf" label="red" template_qid="1" kernelopts="iommu=soft swiotlb=4096" memory="200" default_user="user" volatile_img="volatile.img" services="{'ntpd': False, 'meminfo-writer': False}" maxmem="1535" pcidevs="['02:00.0', '03:00.0']" name="netvm" netid="1" private_img="private.img" vcpus="2" root_img="root.img" debug="False" dir_path="/var/lib/qubes/servicevms/netvm"/>
  36. <QubesProxyVm installed_by_rpm="False" kernel="3.7.6-2" uses_default_kernelopts="True" qid="3" include_in_backups="True" uses_default_kernel="True" qrexec_timeout="60" internal="False" conf_file="firewallvm.conf" label="green" template_qid="1" kernelopts="" memory="200" default_user="user" netvm_qid="2" volatile_img="volatile.img" services="{'meminfo-writer': True}" maxmem="1535" pcidevs="[]" name="firewallvm" netid="2" private_img="private.img" vcpus="2" root_img="root.img" debug="False" dir_path="/var/lib/qubes/servicevms/firewallvm"/>
  37. <QubesAppVm installed_by_rpm="False" kernel="3.7.6-2" uses_default_kernelopts="True" qid="4" include_in_backups="True" uses_default_kernel="True" qrexec_timeout="60" internal="True" conf_file="fedora-18-x64-dvm.conf" label="gray" template_qid="1" kernelopts="" memory="400" default_user="user" netvm_qid="3" uses_default_netvm="True" volatile_img="volatile.img" services="{'meminfo-writer': True}" maxmem="1535" pcidevs="[]" name="fedora-18-x64-dvm" private_img="private.img" vcpus="1" root_img="root.img" debug="False" dir_path="/var/lib/qubes/appvms/fedora-18-x64-dvm"/>
  38. <QubesAppVm installed_by_rpm="False" kernel="3.7.6-2" uses_default_kernelopts="True" qid="5" include_in_backups="True" uses_default_kernel="True" qrexec_timeout="60" internal="False" conf_file="test-work.conf" label="green" template_qid="1" kernelopts="" memory="400" default_user="user" netvm_qid="3" uses_default_netvm="True" volatile_img="volatile.img" services="{'meminfo-writer': True}" maxmem="1535" pcidevs="[]" name="test-work" private_img="private.img" vcpus="2" root_img="root.img" debug="False" dir_path="/var/lib/qubes/appvms/test-work"/>
  39. <QubesAppVm installed_by_rpm="False" kernel="3.7.6-2" uses_default_kernelopts="True" qid="6" include_in_backups="True" uses_default_kernel="True" qrexec_timeout="60" internal="False" conf_file="banking.conf" label="green" template_qid="1" kernelopts="" memory="400" default_user="user" netvm_qid="3" uses_default_netvm="True" volatile_img="volatile.img" services="{'meminfo-writer': True}" maxmem="1535" pcidevs="[]" name="banking" private_img="private.img" vcpus="2" root_img="root.img" debug="False" dir_path="/var/lib/qubes/appvms/banking"/>
  40. <QubesAppVm installed_by_rpm="False" kernel="3.7.6-2" uses_default_kernelopts="True" qid="7" include_in_backups="True" uses_default_kernel="True" qrexec_timeout="60" internal="False" conf_file="personal.conf" label="yellow" template_qid="1" kernelopts="" memory="400" default_user="user" netvm_qid="3" uses_default_netvm="True" volatile_img="volatile.img" services="{'meminfo-writer': True}" maxmem="1535" pcidevs="[]" name="personal" private_img="private.img" vcpus="2" root_img="root.img" debug="False" dir_path="/var/lib/qubes/appvms/personal"/>
  41. <QubesAppVm installed_by_rpm="False" kernel="3.7.6-2" uses_default_kernelopts="True" qid="8" include_in_backups="True" uses_default_kernel="True" qrexec_timeout="60" internal="False" conf_file="untrusted.conf" label="red" template_qid="1" kernelopts="" memory="400" default_user="user" netvm_qid="12" uses_default_netvm="False" volatile_img="volatile.img" services="{'meminfo-writer': True}" maxmem="1535" pcidevs="[]" name="untrusted" private_img="private.img" vcpus="2" root_img="root.img" debug="False" dir_path="/var/lib/qubes/appvms/untrusted"/>
  42. <QubesTemplateVm installed_by_rpm="False" kernel="3.7.6-2" uses_default_kernelopts="True" qid="9" include_in_backups="True" uses_default_kernel="True" qrexec_timeout="60" internal="False" conf_file="test-template-clone.conf" label="green" template_qid="none" kernelopts="" memory="400" default_user="user" netvm_qid="3" uses_default_netvm="True" volatile_img="volatile.img" services="{'meminfo-writer': True}" maxmem="1535" pcidevs="[]" name="test-template-clone" private_img="private.img" vcpus="2" root_img="root.img" debug="False" dir_path="/var/lib/qubes/vm-templates/test-template-clone"/>
  43. <QubesAppVm installed_by_rpm="False" kernel="3.7.6-2" uses_default_kernelopts="True" qid="10" include_in_backups="True" uses_default_kernel="True" qrexec_timeout="60" internal="False" conf_file="test-custom-template-appvm.conf" label="yellow" template_qid="9" kernelopts="" memory="400" default_user="user" netvm_qid="3" uses_default_netvm="True" volatile_img="volatile.img" services="{'meminfo-writer': True}" maxmem="1535" pcidevs="[]" name="test-custom-template-appvm" private_img="private.img" vcpus="2" root_img="root.img" debug="False" dir_path="/var/lib/qubes/appvms/test-custom-template-appvm"/>
  44. <QubesAppVm installed_by_rpm="False" kernel="3.7.6-2" uses_default_kernelopts="True" qid="11" include_in_backups="True" uses_default_kernel="True" qrexec_timeout="60" internal="False" conf_file="test-standalonevm.conf" label="blue" template_qid="none" kernelopts="" memory="400" default_user="user" netvm_qid="3" uses_default_netvm="True" volatile_img="volatile.img" services="{'meminfo-writer': True}" maxmem="1535" pcidevs="[]" name="test-standalonevm" private_img="private.img" vcpus="2" root_img="root.img" debug="False" dir_path="/var/lib/qubes/appvms/test-standalonevm"/>
  45. <QubesProxyVm installed_by_rpm="False" kernel="3.7.6-2" uses_default_kernelopts="True" qid="12" include_in_backups="True" uses_default_kernel="True" qrexec_timeout="60" internal="False" conf_file="test-testproxy.conf" label="red" template_qid="1" kernelopts="" memory="200" default_user="user" netvm_qid="3" volatile_img="volatile.img" services="{'meminfo-writer': True}" maxmem="1535" pcidevs="[]" name="test-testproxy" netid="3" private_img="private.img" vcpus="2" root_img="root.img" debug="False" dir_path="/var/lib/qubes/servicevms/test-testproxy"/>
  46. <QubesProxyVm installed_by_rpm="False" kernel="3.7.6-2" uses_default_kernelopts="True" qid="13" include_in_backups="True" uses_default_kernel="True" qrexec_timeout="60" internal="False" conf_file="testproxy2.conf" label="red" template_qid="9" kernelopts="" memory="200" default_user="user" netvm_qid="2" volatile_img="volatile.img" services="{'meminfo-writer': True}" maxmem="1535" pcidevs="[]" name="testproxy2" netid="4" private_img="private.img" vcpus="2" root_img="root.img" debug="False" dir_path="/var/lib/qubes/servicevms/testproxy2"/>
  47. <QubesHVm installed_by_rpm="False" netvm_qid="none" qid="14" include_in_backups="True" timezone="localtime" qrexec_timeout="60" conf_file="test-testhvm.conf" label="purple" template_qid="none" internal="False" memory="512" uses_default_netvm="True" services="{'meminfo-writer': False}" default_user="user" pcidevs="[]" name="test-testhvm" qrexec_installed="False" private_img="private.img" drive="None" vcpus="2" root_img="root.img" guiagent_installed="False" debug="False" dir_path="/var/lib/qubes/appvms/test-testhvm"/>
  48. </QubesVmCollection>
  49. """
  50. APPTEMPLATE_R2B2 = """
  51. [Desktop Entry]
  52. Name=%VMNAME%: {name}
  53. GenericName=%VMNAME%: {name}
  54. GenericName[ca]=%VMNAME%: Navegador web
  55. GenericName[cs]=%VMNAME%: Webový prohlížeč
  56. GenericName[es]=%VMNAME%: Navegador web
  57. GenericName[fa]=%VMNAME%: مرورر اینترنتی
  58. GenericName[fi]=%VMNAME%: WWW-selain
  59. GenericName[fr]=%VMNAME%: Navigateur Web
  60. GenericName[hu]=%VMNAME%: Webböngésző
  61. GenericName[it]=%VMNAME%: Browser Web
  62. GenericName[ja]=%VMNAME%: ウェブ・ブラウザ
  63. GenericName[ko]=%VMNAME%: 웹 브라우저
  64. GenericName[nb]=%VMNAME%: Nettleser
  65. GenericName[nl]=%VMNAME%: Webbrowser
  66. GenericName[nn]=%VMNAME%: Nettlesar
  67. GenericName[no]=%VMNAME%: Nettleser
  68. GenericName[pl]=%VMNAME%: Przeglądarka WWW
  69. GenericName[pt]=%VMNAME%: Navegador Web
  70. GenericName[pt_BR]=%VMNAME%: Navegador Web
  71. GenericName[sk]=%VMNAME%: Internetový prehliadač
  72. GenericName[sv]=%VMNAME%: Webbläsare
  73. Comment={comment}
  74. Comment[ca]=Navegueu per el web
  75. Comment[cs]=Prohlížení stránek World Wide Webu
  76. Comment[de]=Im Internet surfen
  77. Comment[es]=Navegue por la web
  78. Comment[fa]=صفحات شبه جهانی اینترنت را مرور نمایید
  79. Comment[fi]=Selaa Internetin WWW-sivuja
  80. Comment[fr]=Navigue sur Internet
  81. Comment[hu]=A világháló böngészése
  82. Comment[it]=Esplora il web
  83. Comment[ja]=ウェブを閲覧します
  84. Comment[ko]=웹을 돌아 다닙니다
  85. Comment[nb]=Surf på nettet
  86. Comment[nl]=Verken het internet
  87. Comment[nn]=Surf på nettet
  88. Comment[no]=Surf på nettet
  89. Comment[pl]=Przeglądanie stron WWW
  90. Comment[pt]=Navegue na Internet
  91. Comment[pt_BR]=Navegue na Internet
  92. Comment[sk]=Prehliadanie internetu
  93. Comment[sv]=Surfa på webben
  94. Exec=qvm-run -q --tray -a %VMNAME% '{command} %u'
  95. Categories=Network;WebBrowser;
  96. X-Qubes-VmName=%VMNAME%
  97. Icon=%VMDIR%/icon.png
  98. """
  99. QUBESXML_R1 = """<?xml version='1.0' encoding='UTF-8'?>
  100. <QubesVmCollection clockvm="2" default_fw_netvm="2" default_kernel="3.2.7-10" default_netvm="3" default_template="1" updatevm="3"><QubesTemplateVm conf_file="fedora-17-x64.conf" debug="False" default_user="user" dir_path="/var/lib/qubes/vm-templates/fedora-17-x64" include_in_backups="True" installed_by_rpm="True" internal="False" kernel="3.2.7-10" kernelopts="" label="gray" maxmem="4063" memory="400" name="fedora-17-x64" netvm_qid="3" pcidevs="[]" private_img="private.img" qid="1" root_img="root.img" services="{&apos;meminfo-writer&apos;: True}" template_qid="none" uses_default_kernel="True" uses_default_kernelopts="True" uses_default_netvm="True" vcpus="2" volatile_img="volatile.img" /><QubesNetVm conf_file="netvm.conf" debug="False" default_user="user" dir_path="/var/lib/qubes/servicevms/netvm" include_in_backups="True" installed_by_rpm="False" internal="False" kernel="3.2.7-10" kernelopts="iommu=soft swiotlb=2048" label="red" maxmem="4063" memory="200" name="netvm" netid="1" pcidevs="[&apos;00:19.0&apos;, &apos;03:00.0&apos;]" private_img="private.img" qid="2" root_img="root.img" services="{&apos;ntpd&apos;: False, &apos;meminfo-writer&apos;: False}" template_qid="1" uses_default_kernel="True" uses_default_kernelopts="True" vcpus="2" volatile_img="volatile.img" /><QubesProxyVm conf_file="firewallvm.conf" debug="False" default_user="user" dir_path="/var/lib/qubes/servicevms/firewallvm" include_in_backups="True" installed_by_rpm="False" internal="False" kernel="3.2.7-10" kernelopts="" label="green" maxmem="4063" memory="200" name="firewallvm" netid="2" netvm_qid="2" pcidevs="[]" private_img="private.img" qid="3" root_img="root.img" services="{&apos;meminfo-writer&apos;: True}" template_qid="1" uses_default_kernel="True" uses_default_kernelopts="True" vcpus="2" volatile_img="volatile.img" /><QubesAppVm conf_file="fedora-17-x64-dvm.conf" debug="False" default_user="user" dir_path="/var/lib/qubes/appvms/fedora-17-x64-dvm" include_in_backups="True" installed_by_rpm="False" internal="True" kernel="3.2.7-10" kernelopts="" label="gray" maxmem="4063" memory="400" name="fedora-17-x64-dvm" netvm_qid="3" pcidevs="[]" private_img="private.img" qid="4" root_img="root.img" services="{&apos;meminfo-writer&apos;: True}" template_qid="1" uses_default_kernel="True" uses_default_kernelopts="True" uses_default_netvm="True" vcpus="1" volatile_img="volatile.img" /><QubesAppVm conf_file="test-work.conf" debug="False" default_user="user" dir_path="/var/lib/qubes/appvms/test-work" include_in_backups="True" installed_by_rpm="False" internal="False" kernel="3.2.7-10" kernelopts="" label="green" maxmem="4063" memory="400" name="test-work" netvm_qid="3" pcidevs="[]" private_img="private.img" qid="5" root_img="root.img" services="{&apos;meminfo-writer&apos;: True}" template_qid="1" uses_default_kernel="True" uses_default_kernelopts="True" uses_default_netvm="True" vcpus="2" volatile_img="volatile.img" /><QubesAppVm conf_file="personal.conf" debug="False" default_user="user" dir_path="/var/lib/qubes/appvms/personal" include_in_backups="True" installed_by_rpm="False" internal="False" kernel="3.2.7-10" kernelopts="" label="yellow" maxmem="4063" memory="400" name="personal" netvm_qid="3" pcidevs="[]" private_img="private.img" qid="6" root_img="root.img" services="{&apos;meminfo-writer&apos;: True}" template_qid="1" uses_default_kernel="True" uses_default_kernelopts="True" uses_default_netvm="True" vcpus="2" volatile_img="volatile.img" /><QubesAppVm conf_file="banking.conf" debug="False" default_user="user" dir_path="/var/lib/qubes/appvms/banking" include_in_backups="True" installed_by_rpm="False" internal="False" kernel="3.2.7-10" kernelopts="" label="green" maxmem="4063" memory="400" name="banking" netvm_qid="3" pcidevs="[]" private_img="private.img" qid="7" root_img="root.img" services="{&apos;meminfo-writer&apos;: True}" template_qid="1" uses_default_kernel="True" uses_default_kernelopts="True" uses_default_netvm="True" vcpus="2" volatile_img="volatile.img" /><QubesAppVm conf_file="untrusted.conf" debug="False" default_user="user" dir_path="/var/lib/qubes/appvms/untrusted" include_in_backups="True" installed_by_rpm="False" internal="False" kernel="3.2.7-10" kernelopts="" label="red" maxmem="4063" memory="400" name="untrusted" netvm_qid="3" pcidevs="[]" private_img="private.img" qid="8" root_img="root.img" services="{&apos;meminfo-writer&apos;: True}" template_qid="1" uses_default_kernel="True" uses_default_kernelopts="True" uses_default_netvm="True" vcpus="2" volatile_img="volatile.img" /><QubesAppVm conf_file="test-standalonevm.conf" debug="False" default_user="user" dir_path="/var/lib/qubes/appvms/test-standalonevm" include_in_backups="True" installed_by_rpm="False" internal="False" kernel="None" kernelopts="" label="red" maxmem="4063" memory="400" name="test-standalonevm" netvm_qid="3" pcidevs="[]" private_img="private.img" qid="9" root_img="root.img" services="{&apos;meminfo-writer&apos;: True}" template_qid="none" uses_default_kernel="False" uses_default_kernelopts="True" uses_default_netvm="True" vcpus="2" volatile_img="volatile.img" /><QubesAppVm conf_file="test-testvm.conf" debug="False" default_user="user" dir_path="/var/lib/qubes/appvms/test-testvm" include_in_backups="True" installed_by_rpm="False" internal="False" kernel="3.2.7-10" kernelopts="" label="red" mac="00:16:3E:5E:6C:55" maxmem="4063" memory="400" name="test-testvm" netvm_qid="3" pcidevs="[]" private_img="private.img" qid="10" root_img="root.img" services="{&apos;meminfo-writer&apos;: True}" template_qid="1" uses_default_kernel="True" uses_default_kernelopts="True" uses_default_netvm="True" vcpus="2" volatile_img="volatile.img" /><QubesTemplateVm conf_file="test-template-clone.conf" debug="False" default_user="user" dir_path="/var/lib/qubes/vm-templates/test-template-clone" include_in_backups="True" installed_by_rpm="False" internal="False" kernel="3.2.7-10" kernelopts="" label="gray" maxmem="4063" memory="400" name="test-template-clone" netvm_qid="3" pcidevs="[]" private_img="private.img" qid="11" root_img="root.img" services="{&apos;meminfo-writer&apos;: True}" template_qid="none" uses_default_kernel="True" uses_default_kernelopts="True" uses_default_netvm="True" vcpus="2" volatile_img="volatile.img" /><QubesAppVm conf_file="test-custom-template-appvm.conf" debug="False" default_user="user" dir_path="/var/lib/qubes/appvms/test-custom-template-appvm" include_in_backups="True" installed_by_rpm="False" internal="False" kernel="3.2.7-10" kernelopts="" label="yellow" maxmem="4063" memory="400" name="test-custom-template-appvm" netvm_qid="3" pcidevs="[]" private_img="private.img" qid="12" root_img="root.img" services="{&apos;meminfo-writer&apos;: True}" template_qid="11" uses_default_kernel="True" uses_default_kernelopts="True" uses_default_netvm="True" vcpus="2" volatile_img="volatile.img" /><QubesProxyVm conf_file="test-testproxy.conf" debug="False" default_user="user" dir_path="/var/lib/qubes/servicevms/test-testproxy" include_in_backups="True" installed_by_rpm="False" internal="False" kernel="3.2.7-10" kernelopts="" label="yellow" maxmem="4063" memory="200" name="test-testproxy" netid="3" netvm_qid="2" pcidevs="[]" private_img="private.img" qid="13" root_img="root.img" services="{&apos;meminfo-writer&apos;: True}" template_qid="1" uses_default_kernel="True" uses_default_kernelopts="True" vcpus="2" volatile_img="volatile.img" /></QubesVmCollection>
  101. """
  102. class BackupCompatibilityTests(unittest.TestCase):
  103. def setUp(self):
  104. self.error_detected = Queue()
  105. self.verbose = False
  106. self.qc = QubesVmCollection()
  107. self.reload_qc()
  108. self.backupdir = os.path.join(os.environ["HOME"], "test-backup")
  109. os.mkdir(self.backupdir)
  110. def tearDown(self):
  111. vmlist = [vm for vm in self.qc.values() if vm.name.startswith(
  112. VM_PREFIX)]
  113. self.remove_vms(vmlist)
  114. shutil.rmtree(self.backupdir)
  115. def reload_qc(self):
  116. self.qc.lock_db_for_reading()
  117. self.qc.load()
  118. self.qc.unlock_db()
  119. def print_progress(self, progress):
  120. if self.verbose:
  121. print >> sys.stderr, "\r-> Backing up files: {0}%...".format(progress)
  122. def error_callback(self, message):
  123. self.error_detected.put(message)
  124. if self.verbose:
  125. print >> sys.stderr, "ERROR: {0}".format(message)
  126. def print_callback(self, msg):
  127. if self.verbose:
  128. print msg
  129. def fill_image(self, path, size=None, sparse=False):
  130. block_size = 4096
  131. if self.verbose:
  132. print >>sys.stderr, "-> Filling %s" % path
  133. f = open(path, 'w+')
  134. if size is None:
  135. f.seek(0, 2)
  136. size = f.tell()
  137. f.seek(0)
  138. for block_num in xrange(size/block_size):
  139. f.write('a' * block_size)
  140. if sparse:
  141. f.seek(block_size, 1)
  142. f.close()
  143. def create_sparse(self, path, size):
  144. f = open(path, "w")
  145. f.truncate(size)
  146. f.close()
  147. def remove_vms(self, vms):
  148. self.qc.lock_db_for_writing()
  149. self.qc.load()
  150. for vm in vms:
  151. if isinstance(vm, str):
  152. vm = self.qc.get_vm_by_name(vm)
  153. else:
  154. vm = self.qc[vm.qid]
  155. if self.verbose:
  156. print >>sys.stderr, "-> Removing %s" % vm.name
  157. vm.remove_from_disk()
  158. self.qc.pop(vm.qid)
  159. self.qc.save()
  160. self.qc.unlock_db()
  161. def restore_backup(self, source=None, appvm=None, options=None):
  162. if source is None:
  163. backupfile = os.path.join(self.backupdir,
  164. sorted(os.listdir(self.backupdir))[-1])
  165. else:
  166. backupfile = source
  167. try:
  168. backup_info = backup.backup_restore_prepare(
  169. backupfile, "qubes", print_callback=self.print_callback,
  170. appvm=appvm, options=options)
  171. except QubesException as e: self.fail(
  172. "QubesException during backup_restore_prepare: %s" % str(e))
  173. if self.verbose:
  174. backup.backup_restore_print_summary(backup_info)
  175. try:
  176. backup.backup_restore_do(
  177. backup_info,
  178. print_callback=self.print_callback if self.verbose else None,
  179. error_callback=self.error_callback)
  180. except QubesException as e:
  181. self.fail("QubesException during backup_restore_do: %s" % str(e))
  182. errors = []
  183. while not self.error_detected.empty():
  184. errors.append(self.error_detected.get())
  185. self.assertTrue(len(errors) == 0,
  186. "Error(s) detected during backup_restore_do: %s" %
  187. '\n'.join(errors))
  188. if os.path.isfile(backupfile):
  189. os.unlink(backupfile)
  190. def create_whitelisted_appmenus(self, filename):
  191. f = open(filename, "w")
  192. f.write("gnome-terminal.desktop\n")
  193. f.write("nautilus.desktop\n")
  194. f.write("firefox.desktop\n")
  195. f.write("mozilla-thunderbird.desktop\n")
  196. f.write("libreoffice-startcenter.desktop\n")
  197. f.close()
  198. def create_appmenus(self, dir, template, list):
  199. for name in list:
  200. f = open(os.path.join(dir, name + ".desktop"), "w")
  201. f.write(template.format(name=name, comment=name, command=name))
  202. f.close()
  203. def create_private_img(self, filename):
  204. self.create_sparse(filename, 2*2**30)
  205. subprocess.check_call(["/usr/sbin/mkfs.ext4", "-q", "-F", filename])
  206. def create_volatile_img(self, filename):
  207. self.create_sparse(filename, 11.5*2**30)
  208. sfdisk_input="0,1024,S\n,10240,L\n"
  209. p = subprocess.Popen(["/usr/sbin/sfdisk", "--no-reread", "-u",
  210. "M",
  211. filename], stdout=open("/dev/null","w"),
  212. stderr=subprocess.STDOUT, stdin=subprocess.PIPE)
  213. p.communicate(input=sfdisk_input)
  214. self.assertEqual(p.returncode, 0, "sfdisk failed with code %d" % p
  215. .returncode)
  216. # TODO: mkswap
  217. def fullpath(self, name):
  218. return os.path.join(self.backupdir, name)
  219. def create_v1_files(self, r2b2=False):
  220. appmenus_list = [
  221. "firefox", "gnome-terminal", "evince", "evolution",
  222. "mozilla-thunderbird", "libreoffice-startcenter", "nautilus",
  223. "gedit", "gpk-update-viewer", "gpk-application"
  224. ]
  225. os.mkdir(self.fullpath("appvms"))
  226. os.mkdir(self.fullpath("servicevms"))
  227. os.mkdir(self.fullpath("vm-templates"))
  228. # normal AppVM
  229. os.mkdir(self.fullpath("appvms/test-work"))
  230. self.create_whitelisted_appmenus(self.fullpath(
  231. "appvms/test-work/whitelisted-appmenus.list"))
  232. os.symlink("/usr/share/qubes/icons/green.png",
  233. self.fullpath("appvms/test-work/icon.png"))
  234. self.create_private_img(self.fullpath("appvms/test-work/private.img"))
  235. # StandaloneVM
  236. os.mkdir(self.fullpath("appvms/test-standalonevm"))
  237. self.create_whitelisted_appmenus(self.fullpath(
  238. "appvms/test-standalonevm/whitelisted-appmenus.list"))
  239. os.symlink("/usr/share/qubes/icons/blue.png",
  240. self.fullpath("appvms/test-standalonevm/icon.png"))
  241. self.create_private_img(self.fullpath(
  242. "appvms/test-standalonevm/private.img"))
  243. self.create_sparse(
  244. self.fullpath("appvms/test-standalonevm/root.img"), 10*2**30)
  245. self.fill_image(self.fullpath("appvms/test-standalonevm/root.img"),
  246. 100*1024*1024, True)
  247. os.mkdir(self.fullpath("appvms/test-standalonevm/apps.templates"))
  248. self.create_appmenus(self.fullpath("appvms/test-standalonevm/apps"
  249. ".templates"),
  250. APPTEMPLATE_R2B2,
  251. appmenus_list)
  252. os.mkdir(self.fullpath("appvms/test-standalonevm/kernels"))
  253. for k_file in ["initramfs", "vmlinuz", "modules.img"]:
  254. self.fill_image(self.fullpath("appvms/test-standalonevm/kernels/"
  255. + k_file), 10*1024*1024)
  256. # VM based on custom template
  257. subprocess.check_call(
  258. ["/bin/cp", "-a", self.fullpath("appvms/test-work"),
  259. self.fullpath("appvms/test-custom-template-appvm")])
  260. # HVM
  261. if r2b2:
  262. subprocess.check_call(
  263. ["/bin/cp", "-a", self.fullpath("appvms/test-standalonevm"),
  264. self.fullpath("appvms/test-testhvm")])
  265. # ProxyVM
  266. os.mkdir(self.fullpath("servicevms/test-testproxy"))
  267. self.create_whitelisted_appmenus(self.fullpath(
  268. "servicevms/test-testproxy/whitelisted-appmenus.list"))
  269. self.create_private_img(
  270. self.fullpath("servicevms/test-testproxy/private.img"))
  271. # Custom template
  272. os.mkdir(self.fullpath("vm-templates/test-template-clone"))
  273. self.create_private_img(
  274. self.fullpath("vm-templates/test-template-clone/private.img"))
  275. self.create_sparse(self.fullpath(
  276. "vm-templates/test-template-clone/root-cow.img"), 10*2**30)
  277. self.create_sparse(self.fullpath(
  278. "vm-templates/test-template-clone/root.img"), 10*2**30)
  279. self.fill_image(self.fullpath(
  280. "vm-templates/test-template-clone/root.img"), 1*2**30, True)
  281. self.create_volatile_img(self.fullpath(
  282. "vm-templates/test-template-clone/volatile.img"))
  283. subprocess.check_call([
  284. "/bin/tar", "cS",
  285. "-f", self.fullpath(
  286. "vm-templates/test-template-clone/clean-volatile.img.tar"),
  287. "-C", self.fullpath("vm-templates/test-template-clone"),
  288. "volatile.img"])
  289. self.create_whitelisted_appmenus(self.fullpath(
  290. "vm-templates/test-template-clone/whitelisted-appmenus.list"))
  291. self.create_whitelisted_appmenus(self.fullpath(
  292. "vm-templates/test-template-clone/vm-whitelisted-appmenus.list"))
  293. if r2b2:
  294. self.create_whitelisted_appmenus(self.fullpath(
  295. "vm-templates/test-template-clone/netvm-whitelisted-appmenus"
  296. ".list"))
  297. os.symlink("/usr/share/qubes/icons/green.png",
  298. self.fullpath("vm-templates/test-template-clone/icon.png"))
  299. os.mkdir(
  300. self.fullpath("vm-templates/test-template-clone/apps.templates"))
  301. self.create_appmenus(
  302. self.fullpath("vm-templates/test-template-clone/apps.templates"),
  303. APPTEMPLATE_R2B2,
  304. appmenus_list)
  305. os.mkdir(self.fullpath("vm-templates/test-template-clone/apps"))
  306. self.create_appmenus(
  307. self.fullpath("vm-templates/test-template-clone/apps"),
  308. APPTEMPLATE_R2B2.replace("%VMNAME%", "test-template-clone")
  309. .replace("%VMDIR%", self.fullpath(
  310. "vm-templates/test-template-clone")),
  311. appmenus_list)
  312. def test_r2b2(self):
  313. self.create_v1_files(r2b2=True)
  314. f = open(self.fullpath("qubes.xml"), "w")
  315. f.write(QUBESXML_R2B2)
  316. f.close()
  317. self.restore_backup(self.backupdir, options={
  318. 'use-default-template': True,
  319. })
  320. self.reload_qc()
  321. self.assertIsNotNone(self.qc.get_vm_by_name("test-template-clone"))
  322. self.assertIsNotNone(self.qc.get_vm_by_name("test-testproxy"))
  323. self.assertIsNotNone(self.qc.get_vm_by_name("test-work"))
  324. self.assertIsNotNone(self.qc.get_vm_by_name("test-testhvm"))
  325. self.assertIsNotNone(self.qc.get_vm_by_name("test-standalonevm"))
  326. self.assertIsNotNone(self.qc.get_vm_by_name(
  327. "test-custom-template-appvm"))
  328. self.assertEqual(self.qc.get_vm_by_name("test-custom-template-appvm")
  329. .template,
  330. self.qc.get_vm_by_name("test-template-clone"))
  331. def test_r1(self):
  332. self.create_v1_files(r2b2=False)
  333. f = open(self.fullpath("qubes.xml"), "w")
  334. f.write(QUBESXML_R1)
  335. f.close()
  336. self.restore_backup(self.backupdir, options={
  337. 'use-default-template': True,
  338. })
  339. self.reload_qc()
  340. self.assertIsNotNone(self.qc.get_vm_by_name("test-template-clone"))
  341. self.assertIsNotNone(self.qc.get_vm_by_name("test-testproxy"))
  342. self.assertIsNotNone(self.qc.get_vm_by_name("test-work"))
  343. self.assertIsNotNone(self.qc.get_vm_by_name("test-standalonevm"))
  344. self.assertIsNotNone(self.qc.get_vm_by_name(
  345. "test-custom-template-appvm"))
  346. self.assertEqual(self.qc.get_vm_by_name("test-custom-template-appvm")
  347. .template,
  348. self.qc.get_vm_by_name("test-template-clone"))