diff --git a/examples/specs/5-x86-g-iso-to-tar.spec b/examples/specs/5-x86-g-iso-to-tar.spec new file mode 100644 index 0000000..bf21150 --- /dev/null +++ b/examples/specs/5-x86-g-iso-to-tar.spec @@ -0,0 +1,82 @@ +# Sabayon Linux 5 x86 GNOME Molecule ISO to compressed tar +# The aim of this spec file is make easily scriptable the creation of tar.* +# files generated off a Sabayon Linux ISO Live system environment. +# This, for example, enables users to easily create OpenVZ templates of any +# existing Sabayon Linux ISO image. +# squashfs needed + +# Define an alternative execution strategy, in this case, the value must be +# "iso_to_tar" +execution_strategy: iso_to_tar + +# pre chroot command, example, for 32bit chroots on 64bit system, you always +# have to append "linux32" this is useful for inner_chroot_script +prechroot: linux32 + +# Path to source ISO file (MANDATORY) +source_iso: /sabayon/iso_images/Sabayon_5.0_G.iso + +# Outer chroot script command, to be executed outside destination chroot before +# before entering it (and before inner_chroot_script) +# outer_chroot_script: /path/to/script/to/be/executed/outside + +# Inner chroot script command, to be executed inside destination chroot before packing it +# - kmerge.sh - setup kernel bins +# inner_chroot_script: /sabayon/scripts/inner_chroot_script.sh + +# Outer chroot script command, to be executed outside destination chroot before +# before entering it (and AFTER inner_chroot_script) +# outer_chroot_script_after: /path/to/script/to/be/executed/outside/after + +# Pre-ISO building script. Hook to be able to copy kernel images in place, for example +# pre_iso_script: /sabayon/scripts/cdroot.py + +# Destination directory for the ISO image path (MANDATORY) +destination_tar_directory: /home/fabio + +# Compression method (default is: gz). Supported compression methods: gz, bz2 +# compression_method: gz + +# Specify an alternative tar file name (tar file name will be automatically +# produced otherwise) +# tar_name: + +# Alternative ISO file mount command (default is: mount -o loop -t iso9660) +# iso_mounter: + +# Alternative ISO umounter command (default is: umount) +# iso_umounter: + +# Alternative squashfs file mount command (default is: mount -o loop -t squashfs) +# squash_mounter: + +# Alternative ISO squashfs umount command (default is: umount) +# squash_umounter: + +# Merge directory with destination LiveCD root (before tarring everything up) +# merge_livecd_root: /put/more/files/onto/CD/root + +# List of packages that would be removed from chrooted system (comma separated) +# packages_to_remove: + +# Custom shell call to packages removal (default is: equo remove) +# custom_packages_remove_cmd: + +# List of packages that would be added from chrooted system (comma separated) +# packages_to_add: + +# Custom shell call to packages add (default is: equo install) +# custom_packages_add_cmd: + +# Custom command for updating repositories (default is: equo update) +# repositories_update_cmd: + +# Determine whether repositories update should be run (if packages_to_add is set) +# (default is: no), values are: yes, no. +# execute_repositories_update: no + +# Directories to remove completely (comma separated) +# paths_to_remove: + +# Directories to empty (comma separated) +# paths_to_empty: diff --git a/molecule/specs/plugins/__init__.py b/molecule/specs/plugins/__init__.py index d0d4c2a..71add4a 100644 --- a/molecule/specs/plugins/__init__.py +++ b/molecule/specs/plugins/__init__.py @@ -18,7 +18,8 @@ from molecule.specs.plugins.builtin import LivecdSpec from molecule.specs.plugins.remaster import RemasterSpec +from molecule.specs.plugins.tar import IsoToTarSpec # FIXME: this will need to be pluggable (and plugin factory is required) SPEC_PLUGS = dict((x.execution_strategy(), x,) for x in \ - (LivecdSpec, RemasterSpec)) + (LivecdSpec, RemasterSpec, IsoToTarSpec)) diff --git a/molecule/specs/plugins/tar.py b/molecule/specs/plugins/tar.py new file mode 100644 index 0000000..79cbeda --- /dev/null +++ b/molecule/specs/plugins/tar.py @@ -0,0 +1,211 @@ +# -*- coding: utf-8 -*- +# Molecule Disc Image builder for Sabayon Linux +# Copyright (C) 2009 Fabio Erculiani +# +# 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; either version 2 of the License, or +# (at your option) any later version. +# +# 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., 675 Mass Ave, Cambridge, MA 02139, USA. + +import os +import tempfile +import shutil + +from molecule.i18n import _ +from molecule.output import blue, darkred +from molecule.specs.skel import GenericExecutionStep, GenericSpec +from molecule.specs.plugins.remaster import IsoUnpackHandler, \ + ChrootHandler +import molecule.utils + +SUPPORTED_COMPRESSION_METHODS = ["bz2", "gz"] + +class TarHandler(GenericExecutionStep): + + _TAR_EXEC = "/bin/tar" + _TAR_COMP_METHODS = { + "gz": "z", + "bz2": "j", + } + + def __init__(self, *args, **kwargs): + GenericExecutionStep.__init__(self, *args, **kwargs) + + def _get_tar_comp_method(self): + comp_method = self.metadata.get('compression_method', "gz") + return TarHandler._TAR_COMP_METHODS[comp_method] + + def setup(self): + # setup compression method, default is gz + self.dest_path = os.path.join( + self.metadata['destination_tar_directory'], + os.path.basename(self.metadata['source_iso']) + ".tar." + \ + self.metadata.get('compression_method', "gz")) + self.chroot_path = self.metadata['chroot_unpack_path'] + + def pre_run(self): + self.Output.updateProgress("[%s|%s] %s" % ( + blue("TarHandler"),darkred(self.spec_name), + _("executing pre_run"), + ) + ) + + def run(self): + self.Output.updateProgress("[%s|%s] %s => %s" % ( + blue("TarHandler"),darkred(self.spec_name), + _("compressing chroot"), + self.chroot_path, + ) + ) + dest_path_dir = os.path.dirname(self.dest_path) + if not os.path.isdir(dest_path_dir) and not \ + os.path.lexists(dest_path_dir): + os.makedirs(dest_path_dir, 0755) + + current_dir = os.getcwd() + # change dir to chroot dir + os.chdir(self.chroot_path) + + args = (TarHandler._TAR_EXEC, "cfp" + self._get_tar_comp_method(), + self.dest_path, ".", "--atime-preserve", "--numeric-owner") + rc = molecule.utils.exec_cmd(args) + os.chdir(current_dir) + if rc != 0: + self.Output.updateProgress("[%s|%s] %s: %s" % ( + blue("TarHandler"), darkred(self.spec_name), + _("chroot compression failed"), rc, + ) + ) + return rc + + return 0 + + def post_run(self): + self.Output.updateProgress("[%s|%s] %s" % ( + blue("TarHandler"),darkred(self.spec_name), + _("executing post_run"), + ) + ) + + def kill(self, success = True): + if not success: + try: + shutil.rmtree(self.metadata['chroot_tmp_dir'], True) + except (shutil.Error, OSError,): + pass + return 0 + +class IsoToTarSpec(GenericSpec): + + @staticmethod + def execution_strategy(): + return "iso_to_tar" + + def supported_compression_method(self, comp_m): + return comp_m in SUPPORTED_COMPRESSION_METHODS + + def vital_parameters(self): + return [ + "source_iso", + "destination_tar_directory", + ] + + def parser_data_path(self): + return { + 'prechroot': { + 'cb': self.valid_exec_first_list_item, + 've': self.ve_string_splitter, + }, + 'source_iso': { + 'cb': self.valid_path_string, + 've': self.ve_string_stripper, + }, + 'tar_name': { + 'cb': self.ne_string, + 've': self.ve_string_stripper, + }, + 'compression_method': { + 'cb': self.supported_compression_method, + 've': self.ve_string_stripper, + }, + 'outer_chroot_script': { + 'cb': self.valid_exec, + 've': self.ve_string_stripper, + }, + 'inner_chroot_script': { + 'cb': self.valid_path_string, + 've': self.ve_string_stripper, + }, + 'outer_chroot_script_after': { + 'cb': self.valid_path_string, + 've': self.ve_string_stripper, + }, + 'destination_tar_directory': { + 'cb': self.valid_dir, + 've': self.ve_string_stripper, + }, + 'iso_mounter': { + 'cb': self.ne_list, + 've': self.ve_string_splitter, + }, + 'iso_umounter': { + 'cb': self.ne_list, + 've': self.ve_string_splitter, + }, + 'squash_mounter': { + 'cb': self.ne_list, + 've': self.ve_string_splitter, + }, + 'squash_umounter': { + 'cb': self.ne_list, + 've': self.ve_string_splitter, + }, + 'merge_livecd_root': { + 'cb': self.valid_dir, + 've': self.ve_string_stripper, + }, + 'custom_packages_remove_cmd': { + 'cb': self.valid_ascii, + 've': self.ve_string_stripper, + }, + 'custom_packages_add_cmd': { + 'cb': self.valid_ascii, + 've': self.ve_string_stripper, + }, + 'packages_to_remove': { + 'cb': self.ne_list, + 've': self.valid_comma_sep_list, + }, + 'packages_to_add': { + 'cb': self.ne_list, + 've': self.valid_comma_sep_list, + }, + 'repositories_update_cmd': { + 'cb': self.ne_list, + 've': self.ve_string_splitter, + }, + 'execute_repositories_update': { + 'cb': self.valid_ascii, + 've': self.ve_string_stripper, + }, + 'paths_to_remove': { + 'cb': self.ne_list, + 've': self.valid_path_list, + }, + 'paths_to_empty': { + 'cb': self.ne_list, + 've': self.valid_path_list, + }, + } + + def get_execution_steps(self): + return [IsoUnpackHandler, ChrootHandler, TarHandler]