core2migration.py 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  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, see <http://www.gnu.org/licenses/>
  21. #
  22. #
  23. import os
  24. import sys
  25. import qubes
  26. import qubes.vm.appvm
  27. import qubes.vm.standalonevm
  28. import qubes.vm.templatevm
  29. import qubes.vm.adminvm
  30. import qubes.ext.r3compatibility
  31. import lxml.etree
  32. import xml.parsers.expat
  33. class AppVM(qubes.vm.appvm.AppVM):
  34. """core2 compatibility AppVM class, with variable dir_path"""
  35. dir_path = qubes.property('dir_path',
  36. default=(lambda self: self.storage.vmdir),
  37. saver=qubes.property.dontsave,
  38. doc="VM storage directory",
  39. )
  40. def is_running(self):
  41. return False
  42. class StandaloneVM(qubes.vm.standalonevm.StandaloneVM):
  43. """core2 compatibility StandaloneVM class, with variable dir_path"""
  44. dir_path = qubes.property('dir_path',
  45. default=(lambda self: self.storage.vmdir),
  46. saver=qubes.property.dontsave,
  47. doc="VM storage directory")
  48. def is_running(self):
  49. return False
  50. class Core2Qubes(qubes.Qubes):
  51. def __init__(self, store=None, load=True, **kwargs):
  52. if store is None:
  53. raise ValueError("store path required")
  54. super(Core2Qubes, self).__init__(store, load, **kwargs)
  55. def load_globals(self, element):
  56. default_template = element.get("default_template")
  57. self.default_template = int(default_template) \
  58. if default_template.lower() != "none" else None
  59. default_netvm = element.get("default_netvm")
  60. if default_netvm is not None:
  61. self.default_netvm = int(default_netvm) \
  62. if default_netvm != "None" else None
  63. default_fw_netvm = element.get("default_fw_netvm")
  64. if default_fw_netvm is not None:
  65. self.default_fw_netvm = int(default_fw_netvm) \
  66. if default_fw_netvm != "None" else None
  67. updatevm = element.get("updatevm")
  68. if updatevm is not None:
  69. self.updatevm = int(updatevm) \
  70. if updatevm != "None" else None
  71. clockvm = element.get("clockvm")
  72. if clockvm is not None:
  73. self.clockvm = int(clockvm) \
  74. if clockvm != "None" else None
  75. self.default_kernel = element.get("default_kernel")
  76. def set_netvm_dependency(self, element):
  77. kwargs = {}
  78. attr_list = ("qid", "uses_default_netvm", "netvm_qid")
  79. for attribute in attr_list:
  80. kwargs[attribute] = element.get(attribute)
  81. vm = self.domains[int(kwargs["qid"])]
  82. if element.get("uses_default_netvm") is None:
  83. uses_default_netvm = True
  84. else:
  85. uses_default_netvm = (
  86. True if element.get("uses_default_netvm") == "True" else False)
  87. if not uses_default_netvm:
  88. netvm_qid = element.get("netvm_qid")
  89. if netvm_qid is None or netvm_qid == "none":
  90. vm.netvm = None
  91. else:
  92. vm.netvm = int(netvm_qid)
  93. # TODO: dispvm_netvm
  94. def load(self):
  95. qubes_store_file = open(self._store, 'r')
  96. try:
  97. qubes_store_file.seek(0)
  98. tree = lxml.etree.parse(qubes_store_file)
  99. except (EnvironmentError,
  100. xml.parsers.expat.ExpatError) as err:
  101. self.log.error(err)
  102. return False
  103. self.labels = {
  104. 1: qubes.Label(1, '0xcc0000', 'red'),
  105. 2: qubes.Label(2, '0xf57900', 'orange'),
  106. 3: qubes.Label(3, '0xedd400', 'yellow'),
  107. 4: qubes.Label(4, '0x73d216', 'green'),
  108. 5: qubes.Label(5, '0x555753', 'gray'),
  109. 6: qubes.Label(6, '0x3465a4', 'blue'),
  110. 7: qubes.Label(7, '0x75507b', 'purple'),
  111. 8: qubes.Label(8, '0x000000', 'black'),
  112. }
  113. self.domains.add(qubes.vm.adminvm.AdminVM(
  114. self, None, qid=0, name='dom0'))
  115. vm_classes = ["TemplateVm", "TemplateHVm",
  116. "AppVm", "HVm", "NetVm", "ProxyVm"]
  117. for (vm_class_name) in vm_classes:
  118. vms_of_class = tree.findall("Qubes" + vm_class_name)
  119. # first non-template based, then template based
  120. sorted_vms_of_class = sorted(vms_of_class,
  121. key=lambda x: str(x.get('template_qid')).lower() != "none")
  122. for element in sorted_vms_of_class:
  123. try:
  124. kwargs = {}
  125. if vm_class_name in ["TemplateVm", "TemplateHVm"]:
  126. vm_class = qubes.vm.templatevm.TemplateVM
  127. elif element.get('template_qid').lower() == "none":
  128. kwargs['dir_path'] = element.get('dir_path')
  129. vm_class = StandaloneVM
  130. else:
  131. kwargs['dir_path'] = element.get('dir_path')
  132. kwargs['template'] = int(element.get('template_qid'))
  133. vm_class = AppVM
  134. # simple attributes
  135. for attr in ['installed_by_rpm', 'include_in_backups',
  136. 'qrexec_timeout', 'internal', 'label', 'name',
  137. 'vcpus', 'memory', 'maxmem', 'default_user',
  138. 'debug', 'pci_strictreset', 'mac', 'autostart']:
  139. value = element.get(attr)
  140. if value:
  141. kwargs[attr] = value
  142. # attributes with default value
  143. for attr in ["kernel", "kernelopts"]:
  144. value = element.get(attr)
  145. if value and value.lower() == "none":
  146. value = None
  147. value_is_default = element.get(
  148. "uses_default_{}".format(attr))
  149. if value_is_default and value_is_default.lower() != \
  150. "true":
  151. kwargs[attr] = value
  152. kwargs['hvm'] = "HVm" in vm_class_name
  153. vm = self.add_new_vm(vm_class,
  154. qid=int(element.get('qid')), **kwargs)
  155. services = element.get('services')
  156. if services:
  157. services = eval(services)
  158. else:
  159. services = {}
  160. for service, value in services.iteritems():
  161. feature = service
  162. for repl_feature, repl_service in \
  163. qubes.ext.r3compatibility.\
  164. R3Compatibility.features_to_services.\
  165. iteritems():
  166. if repl_service == service:
  167. feature = repl_feature
  168. vm.features[feature] = value
  169. for attr in ['backup_content', 'backup_path',
  170. 'backup_size']:
  171. value = element.get(attr)
  172. vm.features[attr.replace('_', '-')] = value
  173. pcidevs = element.get('pcidevs')
  174. if pcidevs:
  175. pcidevs = eval(pcidevs)
  176. for pcidev in pcidevs:
  177. try:
  178. vm.devices["pci"].attach(pcidev)
  179. except qubes.exc.QubesException as e:
  180. self.log.error("VM {}: {}".format(vm.name, str(e)))
  181. except (ValueError, LookupError) as err:
  182. self.log.error("import error ({1}): {2}".format(
  183. vm_class_name, err))
  184. if 'vm' in locals():
  185. del self.domains[vm]
  186. # After importing all VMs, set netvm references, in the same order
  187. for vm_class_name in vm_classes:
  188. for element in tree.findall("Qubes" + vm_class_name):
  189. try:
  190. self.set_netvm_dependency(element)
  191. except (ValueError, LookupError) as err:
  192. self.log.error("VM {}: failed to set netvm dependency: {}".
  193. format(element.get('name'), err))
  194. self.load_globals(tree.getroot())
  195. def save(self):
  196. raise NotImplementedError("Saving old qubes.xml not supported")