From d6f9214cc755292766de5674e61ccee8573b7f6a Mon Sep 17 00:00:00 2001 From: Daniel Silverstone Date: Tue, 14 Aug 2012 10:49:08 +0000 Subject: Initial non-syslinux disk image kind This adds a disk system image kind which does everything the syslinux-disk one does, but without syslinux. It deliberately carries stubbed bootloader operations so that we can later make syslinux-disk inherit from this one and override it. --- morphlib/builder2.py | 136 ++++++++++++++++++++++++++ morphlib/plugins/disk-systembuilder_plugin.py | 27 +++++ without-test-modules | 1 + 3 files changed, 164 insertions(+) create mode 100644 morphlib/plugins/disk-systembuilder_plugin.py diff --git a/morphlib/builder2.py b/morphlib/builder2.py index 6edb7c61..9a8667b4 100644 --- a/morphlib/builder2.py +++ b/morphlib/builder2.py @@ -650,3 +650,139 @@ class Builder(object): # pragma: no cover built_artifacts = o.build_and_cache() logging.debug('Builder.build: done') return built_artifacts + +class DiskImageBuilder(SystemKindBuilder): # pragma: no cover + + system_kind = 'disk' + + def build_and_cache(self): + with self.build_watch('overall-build'): + arch = self.artifact.source.morphology['arch'] + + rootfs_artifact = self.new_artifact( + self.artifact.source.morphology['name'] + '-rootfs') + handle = self.local_artifact_cache.put(rootfs_artifact) + image_name = handle.name + + self._create_image(image_name) + self._partition_image(image_name) + self._install_mbr(arch, image_name) + partition = self._setup_device_mapping(image_name) + + mount_point = None + try: + self._create_fs(partition) + mount_point = self.staging_area.destdir(self.artifact.source) + self._mount(partition, mount_point) + factory_path = os.path.join(mount_point, 'factory') + self._create_subvolume(factory_path) + self.unpack_strata(factory_path) + self.create_fstab(factory_path) + self._create_bootloader_config(factory_path) + self._create_subvolume_snapshot( + mount_point, 'factory', 'factory-run') + factory_run_path = os.path.join(mount_point, 'factory-run') + self._install_boot_files(arch, factory_run_path, mount_point) + self._install_bootloader(mount_point) + self.copy_kernel_into_artifact_cache(factory_path) + self._unmount(mount_point) + except BaseException, e: + logging.error(traceback.format_exc()) + self.app.status(msg='Error while building system', + error=True) + self._unmount(mount_point) + self._undo_device_mapping(image_name) + handle.abort() + raise + + self._undo_device_mapping(image_name) + handle.close() + + self.save_build_times() + return [self.artifact] + + def _create_image(self, image_name): + self.app.status(msg='Creating disk image %(filename)s', + filename=image_name, chatty=True) + with self.build_watch('create-image'): + morphlib.fsutils.create_image( + self.app.runcmd, image_name, + self.artifact.source.morphology['disk-size']) + + def _partition_image(self, image_name): + self.app.status(msg='Partitioning disk image %(filename)s', + filename=image_name) + with self.build_watch('partition-image'): + morphlib.fsutils.partition_image(self.app.runcmd, image_name) + + def _install_mbr(self, arch, image_name): + pass + + def _setup_device_mapping(self, image_name): + self.app.status(msg='Device mapping partitions in %(filename)s', + filename=image_name, chatty=True) + with self.build_watch('setup-device-mapper'): + return morphlib.fsutils.setup_device_mapping(self.app.runcmd, + image_name) + + def _create_fs(self, partition): + self.app.status(msg='Creating filesystem on %(partition)s', + partition=partition, chatty=True) + with self.build_watch('create-filesystem'): + morphlib.fsutils.create_fs(self.app.runcmd, partition) + + def _mount(self, partition, mount_point): + self.app.status(msg='Mounting %(partition)s on %(mount_point)s', + partition=partition, mount_point=mount_point, + chatty=True) + with self.build_watch('mount-filesystem'): + morphlib.fsutils.mount(self.app.runcmd, partition, mount_point) + + def _create_subvolume(self, path): + self.app.status(msg='Creating subvolume %(path)s', + path=path, chatty=True) + with self.build_watch('create-factory-subvolume'): + self.app.runcmd(['btrfs', 'subvolume', 'create', path]) + + def _create_bootloader_config(self, path): + pass + + def _create_subvolume_snapshot(self, path, source, target): + self.app.status(msg='Creating subvolume snapshot ' + '%(source)s to %(target)s', + source=source, target=target, chatty=True) + with self.build_watch('create-runtime-snapshot'): + # sync needed for older versions of btrfs where files aren't + # flushed to disk before they have their contents snapshotted + self.app.runcmd(['sync']) + self.app.runcmd(['btrfs', 'subvolume', 'snapshot', source, target], + cwd=path) + + def _install_boot_files(self, arch, sourcefs, targetfs): + with self.build_watch('install-boot-files'): + if arch in ('x86', 'x86_64'): + self.app.status(msg='Installing boot files into root volume', + chatty=True) + os.mkdir(os.path.join(targetfs, 'boot')) + shutil.copy2(os.path.join(sourcefs, 'boot', 'vmlinuz'), + os.path.join(targetfs, 'boot', 'vmlinuz')) + shutil.copy2(os.path.join(sourcefs, 'boot', 'System.map'), + os.path.join(targetfs, 'boot', 'System.map')) + + def _install_bootloader(self, path): + pass + + def _unmount(self, mount_point): + with self.build_watch('unmount-filesystem'): + if mount_point is not None: + self.app.status(msg='Unmounting %(mount_point)s', + mount_point=mount_point, chatty=True) + morphlib.fsutils.unmount(self.app.runcmd, mount_point) + + def _undo_device_mapping(self, image_name): + self.app.status(msg='Undoing device mappings for %(filename)s', + filename=image_name, chatty=True) + with self.build_watch('undo-device-mapper'): + morphlib.fsutils.undo_device_mapping(self.app.runcmd, image_name) + + diff --git a/morphlib/plugins/disk-systembuilder_plugin.py b/morphlib/plugins/disk-systembuilder_plugin.py new file mode 100644 index 00000000..2ff28722 --- /dev/null +++ b/morphlib/plugins/disk-systembuilder_plugin.py @@ -0,0 +1,27 @@ +# Copyright (C) 2012 Codethink Limited +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; version 2 of the License. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License along +# with this program; if not, write to the Free Software Foundation, Inc., +# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + +import cliapp + +from morphlib.builder2 import DiskImageBuilder + +class DiskBuilderPlugin(cliapp.Plugin): + + def enable(self): + self.app.system_kind_builder_factory.register(DiskImageBuilder) + + def disable(self): + pass diff --git a/without-test-modules b/without-test-modules index aaa796f7..887358c4 100644 --- a/without-test-modules +++ b/without-test-modules @@ -8,6 +8,7 @@ morphlib/app.py morphlib/plugins/hello_plugin.py morphlib/plugins/graphing_plugin.py morphlib/plugins/syslinux-disk-systembuilder_plugin.py +morphlib/plugins/disk-systembuilder_plugin.py morphlib/plugins/tarball-systembuilder_plugin.py morphlib/plugins/show_dependencies_plugin.py morphlib/plugins/update_gits_plugin.py -- cgit v1.2.1