def has_valid_os_image(self): """ Check if OS image exists and is fresh enough. """ if not self.storage.exists(distro.distro_image_filename()): return False os_mtime = self.storage.mtime(distro.distro_image_filename()) delta = datetime.datetime.now() - os_mtime if delta > datetime.timedelta(days=self.config.bootstrap.maxage): log.info("OS image is too old (%d days)" % delta.days) self.storage.delete(distro.distro_image_filename()) return False return True
def handle(self, *args, **options): builder = OSBuilder(settings.UPAAS_CONFIG) if options['force'] or not builder.has_valid_os_image(): if getuid() != 0 and not options['as_user']: log.error("You must run this command as root user, aborting") exit(1) if builder.storage.exists(distro_image_filename()): log.info("Deleting current OS image") try: builder.storage.delete(distro_image_filename()) except StorageError: log.error("Deletion failed") exit(2) try: builder.bootstrap_os() except exceptions.OSBootstrapError: log.error("Bootstrap failed") exit(3) except StorageError: log.error("Upload failed") exit(4) else: log.info("Bootstrap not needed, skipping (use --force to run " "bootstrap anyway)")
def bootstrap_os(self): """ Bootstrap base OS image. """ log.info("Bootstrapping new OS image") # directory is encoded into string to prevent unicode errors directory = tempfile.mkdtemp(dir=self.config.paths.workdir, prefix="upaas_bootstrap_") log.debug("Created temporary directory for bootstrap at " "'%s'" % directory) for cmd in self.config.bootstrap.commands: cmd = cmd.replace("%workdir%", directory) try: commands.execute(cmd, timeout=self.config.bootstrap.timelimit, cwd=directory, env=self.config.bootstrap.env, strip_envs=True) except commands.CommandTimeout as e: log.error("Bootstrap was taking too long and it was killed") kill_and_remove_dir(directory) raise exceptions.OSBootstrapError(e) except commands.CommandFailed as e: log.error("Bootstrap command failed") kill_and_remove_dir(directory) raise exceptions.OSBootstrapError(e) log.info("All commands completed, installing packages") self.install_packages(directory, self.config.bootstrap.packages) log.info("Bootstrap done, packing image") archive_path = os.path.join(directory, "image.tar.gz") if not tar.pack_tar(directory, archive_path, timeout=self.config.bootstrap.timelimit): kill_and_remove_dir(directory) raise exceptions.OSBootstrapError("Tar error") else: log.info("Image packed, uploading") try: self.storage.put(archive_path, distro.distro_image_filename()) except Exception as e: log.error("Upload failed: %s" % e) raise log.info("Image uploaded") kill_and_remove_dir(directory) log.info("All done")
def unpack_os(self, directory, workdir, system_filename=None): empty_os_image = False if not system_filename: system_filename = distro.distro_image_filename() empty_os_image = True os_image_path = os.path.join(directory, "os.image") log.info("Fetching OS image '%s'" % system_filename) try: self.storage.get(system_filename, os_image_path) except StorageError: log.error("Storage error while fetching OS image") return False else: log.info("Unpacking OS image") if not tar.unpack_tar(os_image_path, workdir): log.error("Error while unpacking OS image to '%s'" % workdir) return False # verify if os is working log.info("Checking if OS image is working (will execute /bin/true)") try: with Chroot(workdir): commands.execute('/bin/true', timeout=self.config.commands.timelimit, output_loglevel=logging.INFO) except Exception as e: log.error("Broken OS image! /bin/true failed: %s" % e) if empty_os_image: try: self.storage.delete(system_filename) except StorageError as e: log.error("Storage error while deleting OS image: %s" % e) else: log.info("Deleted broken OS image from storage") self.bootstrap_os() return self.unpack_os(directory, workdir, system_filename=system_filename) return False else: return True