PageRenderTime 48ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/solusos/testsystem.py

https://bitbucket.org/ikeydoherty/packagescripts
Python | 178 lines | 131 code | 28 blank | 19 comment | 27 complexity | ab592b140eed4100c5cfdc509d740372 MD5 | raw file
  1. import sys
  2. try:
  3. from configobj import ConfigObj
  4. except:
  5. print "python-configObj missing!"
  6. sys.exit (1)
  7. import os.path
  8. from solusos.console import *
  9. from solusos.system import UnderlayManager, SystemManager, execute_hide
  10. import commands
  11. import shutil
  12. import time
  13. import glob
  14. # Global configuration file for SolusOS 2
  15. CONFIG_FILE = "/etc/solusos/2.conf"
  16. TEST_SYSTEM_URI = "http://ng.solusos.com/root_32.squashfs"
  17. RESOURCE_DIR = "/usr/share/solusos/resources_2"
  18. class TestSystem:
  19. def __init__(self):
  20. if not os.path.exists (CONFIG_FILE):
  21. print "Configuration file missing"
  22. sys.exit (1)
  23. self.config = ConfigObj (CONFIG_FILE)
  24. self.underlay = self.config ["BuildKit"]["Image"]
  25. if not os.path.exists (self.underlay):
  26. print "The SolusOS 2 underlay has not been installed"
  27. if yes_no ("Download the SolusOS 2 test kit?"):
  28. dire = "/".join (self.underlay.split ("/")[:-1])
  29. if not os.path.exists (dire):
  30. os.makedirs (dire)
  31. UnderlayManager.DownloadUnderlay (TEST_SYSTEM_URI, self.underlay)
  32. else:
  33. print
  34. print_error ("Aborting due to missing underlay system")
  35. sys.exit (1)
  36. # Now check for our loopback file
  37. self.loopback_file = self.config ["Storage"]["LoopbackFile"]
  38. self.generate_loopback = self.config ["Storage"]["AutoGenerate"]
  39. self.loopback_size = int(self.config ["Storage"]["Size"])
  40. self.loopback_filesystem = self.config ["Storage"]["Filesystem"]
  41. self.system_root = self.config ["Storage"]["SystemRoot"]
  42. if not os.path.exists (self.loopback_file):
  43. # Do we create one ?
  44. if not self.generate_loopback:
  45. print_error ("Couldn\'t find the loopback filesystem: %s" % self.loopback_file)
  46. sys.exit (1)
  47. if yes_no ("A %sMiB loopback filesystem will be created for storage\nDo you want to create the %s loopback file?" % (self.loopback_size, self.loopback_file)):
  48. UnderlayManager.CreateLoopbackFile (self.loopback_file, self.loopback_size, self.loopback_filesystem)
  49. else:
  50. print_error ("Aborting due to missing loopback file")
  51. # Check this is a valid filesystem
  52. filetype = commands.getoutput ("file \"%s\"" % self.loopback_file)
  53. if not "filesystem" in filetype.lower():
  54. print_error ("\"%s\" does not contain a valid filesystem" % self.loopback_file)
  55. sys.exit (1)
  56. self.cache_dir = os.path.join (self.system_root, "cache")
  57. self.underlay_dir = os.path.join (self.system_root, "buildkit")
  58. self.union_dir = os.path.join (self.system_root, "union")
  59. # Now we ideally want to mount this baby.
  60. dirs = [ "cache", "buildkit", "union" ]
  61. for dire in dirs:
  62. fpath = os.path.join (self.system_root, dire)
  63. if not os.path.exists (fpath):
  64. os.makedirs (fpath)
  65. def enter_system (self, bind_home=False):
  66. ''' Enter the system '''
  67. # Mount the cache file (i.e. the 500MB filesystem)
  68. options = "loop"
  69. if self.loopback_filesystem == "btrfs":
  70. # Automatically compress a btrfs loopback file
  71. options += ",compress"
  72. self.bind_home = bind_home
  73. SystemManager.mount (self.loopback_file, self.cache_dir, filesystem=None, options=options)
  74. # Mount our root buildkit filesystem
  75. SystemManager.mount (self.underlay, self.underlay_dir, filesystem="squashfs", options="loop,ro")
  76. options = "dirs=%s:%s=ro" % (self.cache_dir, self.underlay_dir)
  77. SystemManager.mount ("none", self.union_dir, filesystem="unionfs", options=options)
  78. # D-BUS.
  79. self.dbus_pid = os.path.join (self.union_dir, "var/run/dbus/pid")
  80. if os.path.exists (self.dbus_pid):
  81. print_info ("Deleting stale D-BUS PID file..")
  82. os.unlink (self.dbus_pid)
  83. # Always ensure the dbus start files exist
  84. lsb_init = os.path.join (self.union_dir, "lib/lsb")
  85. dbus_rc = os.path.join (self.union_dir, "etc/rc.d/init.d")
  86. if not os.path.exists (lsb_init):
  87. source_lsb = os.path.join (RESOURCE_DIR, "data/lsb")
  88. dest_lsb = os.path.join (self.union_dir, "lib/lsb")
  89. print_info ("Copying lsb init functions")
  90. shutil.copytree (source_lsb, dest_lsb)
  91. if not os.path.exists (dbus_rc):
  92. source_dbus = os.path.join (RESOURCE_DIR, "data/init.d")
  93. dest_dbus = os.path.join (self.union_dir, "etc/rc.d/init.d")
  94. print_info ("Copying dbus startup files")
  95. shutil.copytree (source_dbus, dest_dbus)
  96. # Startup dbus
  97. self.dbus_service = "/etc/rc.d/init.d/dbus"
  98. print_info ("Starting the D-Bus systemwide message bus")
  99. execute_hide ("chroot \"%s\" \"%s\" start" % (self.union_dir, self.dbus_service))
  100. # Set up devices + stuff
  101. self.dev_shm_path = os.path.join (self.union_dir, "dev/shm")
  102. if not os.path.exists (self.dev_shm_path):
  103. os.makedirs (self.dev_shm_path)
  104. self.proc_dir = os.path.join (self.union_dir, "proc")
  105. SystemManager.mount ("tmpfs", self.dev_shm_path, filesystem="tmpfs")
  106. SystemManager.mount ("proc", self.proc_dir, filesystem="proc")
  107. # Finally, bind home
  108. if bind_home:
  109. self.home_dir = os.path.join (self.union_dir, "home")
  110. if not os.path.exists (self.home_dir):
  111. os.makedirs (self.home_dir)
  112. SystemManager.mount_home (self.home_dir)
  113. def murder_death_kill (self, be_gentle=False):
  114. ''' Completely and utterly murder all processes in the chroot :) '''
  115. for root in glob.glob ("/proc/*/root"):
  116. try:
  117. link = os.path.realpath (root)
  118. if os.path.abspath (link) == os.path.abspath (self.union_dir):
  119. pid = root.split ("/")[2]
  120. if be_gentle:
  121. os.system ("kill %s" % pid)
  122. else:
  123. os.system ("kill -9 %s" % pid)
  124. except:
  125. pass
  126. def exit_system (self):
  127. ''' Exit the system '''
  128. # Clean up by unmounting for now
  129. if self.bind_home:
  130. print_info ("Unmounting home...")
  131. SystemManager.umount (self.home_dir)
  132. dbus_pid = os.path.join (self.union_dir, "var/run/dbus/pid")
  133. print_info ("Stopping D-BUS...")
  134. with open (dbus_pid, "r") as pid_file:
  135. pid = pid_file.read().strip()
  136. os.system ("kill -9 %s" % pid)
  137. # Safety, gives dbus enough time to die
  138. time.sleep (3)
  139. # Murder the remaining processes
  140. print_info ("Asking all remaining processes to stop...")
  141. self.murder_death_kill (be_gentle=True)
  142. print_info ("Force-kill any remaining processes...")
  143. self.murder_death_kill ()
  144. print_info ("Unmounting virtual filesystems...")
  145. SystemManager.umount (self.dev_shm_path)
  146. SystemManager.umount (self.proc_dir)
  147. print_info ("Unmounting SolusOS 2 system...")
  148. SystemManager.umount (self.union_dir)
  149. SystemManager.umount (self.cache_dir)
  150. SystemManager.umount (self.underlay_dir)