xen.py 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. #!/usr/bin/python2
  2. #
  3. # The Qubes OS Project, http://www.qubes-os.org
  4. #
  5. # Copyright (C) 2013 Marek Marczykowski <marmarek@invisiblethingslab.com>
  6. #
  7. # This program is free software; you can redistribute it and/or
  8. # modify it under the terms of the GNU General Public License
  9. # as published by the Free Software Foundation; either version 2
  10. # of the License, or (at your option) any later version.
  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
  18. # along with this program; if not, write to the Free Software
  19. # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  20. #
  21. #
  22. from __future__ import absolute_import
  23. import os
  24. import os.path
  25. import subprocess
  26. import sys
  27. from qubes.storage import QubesVmStorage
  28. from qubes.qubes import QubesException
  29. class QubesXenVmStorage(QubesVmStorage):
  30. """
  31. Class for VM storage of Xen VMs.
  32. """
  33. def __init__(self, vm, **kwargs):
  34. super(QubesXenVmStorage, self).__init__(vm, **kwargs)
  35. self.root_dev = "xvda"
  36. self.private_dev = "xvdb"
  37. self.volatile_dev = "xvdc"
  38. self.modules_dev = "xvdd"
  39. def _format_disk_dev(self, path, script, vdev, rw=True, type="disk", domain=None):
  40. template = " <disk type='block' device='{type}'>\n" \
  41. " <driver name='phy'/>\n" \
  42. " <source dev='{path}'/>\n" \
  43. " <target dev='{vdev}' bus='xen'/>\n" \
  44. "{params}" \
  45. " </disk>\n"
  46. params = ""
  47. if not rw:
  48. params += " <readonly/>\n"
  49. if domain:
  50. params += " <domain name='%s'/>\n" % domain
  51. if script:
  52. params += " <script path='%s'/>\n" % script
  53. return template.format(path=path, vdev=vdev, type=type,
  54. params=params)
  55. def _get_rootdev(self):
  56. if self.vm.is_template():
  57. return self._format_disk_dev(
  58. "{dir}/root.img:{dir}/root-cow.img".format(
  59. dir=self.vmdir),
  60. "block-origin", self.root_dev, True)
  61. elif self.vm.template:
  62. return self._format_disk_dev(
  63. "{dir}/root.img:{dir}/root-cow.img".format(
  64. dir=self.vm.template.vmdir),
  65. "block-snapshot", self.root_dev, False)
  66. else:
  67. return self._format_disk_dev(
  68. "{dir}/root.img".format(dir=self.vmdir),
  69. None, self.root_dev, True)
  70. def get_config_params(self):
  71. args = {}
  72. args['rootdev'] = self._get_rootdev()
  73. args['privatedev'] = \
  74. self._format_disk_dev(self.private_img,
  75. None, self.private_dev, True)
  76. args['volatiledev'] = \
  77. self._format_disk_dev(self.volatile_img,
  78. None, self.volatile_dev, True)
  79. if self.modules_img is not None:
  80. args['otherdevs'] = \
  81. self._format_disk_dev(self.modules_img,
  82. None, self.modules_dev, self.modules_img_rw)
  83. return args
  84. def create_on_disk_private_img(self, verbose, source_template = None):
  85. if source_template:
  86. template_priv = source_template.private_img
  87. if verbose:
  88. print >> sys.stderr, "--> Copying the template's private image: {0}".\
  89. format(template_priv)
  90. self._copy_file(template_priv, self.private_img)
  91. else:
  92. f_private = open (self.private_img, "a+b")
  93. f_private.truncate (self.private_img_size)
  94. f_private.close ()
  95. def create_on_disk_root_img(self, verbose, source_template = None):
  96. if source_template:
  97. if not self.vm.updateable:
  98. # just use template's disk
  99. return
  100. else:
  101. template_root = source_template.root_img
  102. if verbose:
  103. print >> sys.stderr, "--> Copying the template's root image: {0}".\
  104. format(template_root)
  105. self._copy_file(template_root, self.root_img)
  106. else:
  107. f_root = open (self.root_img, "a+b")
  108. f_root.truncate (self.root_img_size)
  109. f_root.close ()
  110. def resize_private_img(self, size):
  111. f_private = open (self.private_img, "a+b")
  112. f_private.truncate (size)
  113. f_private.close ()
  114. # find loop device if any
  115. p = subprocess.Popen (["sudo", "losetup", "--associated", self.private_img],
  116. stdout=subprocess.PIPE)
  117. result = p.communicate()
  118. m = re.match(r"^(/dev/loop\d+):\s", result[0])
  119. if m is not None:
  120. loop_dev = m.group(1)
  121. # resize loop device
  122. subprocess.check_call(["sudo", "losetup", "--set-capacity", loop_dev])
  123. def commit_template_changes(self):
  124. assert self.vm.is_template()
  125. # TODO: move rootcow_img to this class; the same for vm.is_outdated()
  126. if os.path.exists (self.vm.rootcow_img):
  127. os.rename (self.vm.rootcow_img, self.vm.rootcow_img + '.old')
  128. old_umask = os.umask(002)
  129. f_cow = open (self.vm.rootcow_img, "w")
  130. f_root = open (self.root_img, "r")
  131. f_root.seek(0, os.SEEK_END)
  132. f_cow.truncate (f_root.tell()) # make empty sparse file of the same size as root.img
  133. f_cow.close ()
  134. f_root.close()
  135. os.umask(old_umask)