From: Nikos Skalkotos Date: Wed, 15 Feb 2012 17:19:46 +0000 (+0200) Subject: Initial commit X-Git-Tag: v0.1~157 X-Git-Url: https://code.grnet.gr/git/snf-image-creator/commitdiff_plain/d57775d405ab1c2a208915b8033e875f9d08bbc8 Initial commit --- d57775d405ab1c2a208915b8033e875f9d08bbc8 diff --git a/image_creator/__init__.py b/image_creator/__init__.py new file mode 100644 index 0000000..817a9c6 --- /dev/null +++ b/image_creator/__init__.py @@ -0,0 +1,34 @@ +# Copyright 2011 GRNET S.A. All rights reserved. +# +# Redistribution and use in source and binary forms, with or +# without modification, are permitted provided that the following +# conditions are met: +# +# 1. Redistributions of source code must retain the above +# copyright notice, this list of conditions and the following +# disclaimer. +# +# 2. Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials +# provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS +# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +# The views and conclusions contained in the software and +# documentation are those of the authors and should not be +# interpreted as representing official policies, either expressed +# or implied, of GRNET S.A. + +__version__ = '0.1' diff --git a/image_creator/disk.py b/image_creator/disk.py new file mode 100644 index 0000000..b20ca74 --- /dev/null +++ b/image_creator/disk.py @@ -0,0 +1,106 @@ +#!/usr/bin/env python + +import losetup +import stat +import os +import tempfile +import uuid +import re +from pbs import dmsetup +from pbs import blockdev +from pbs import dd +from pbs import kpartx +from pbs import mount +from pbs import umount + +class Disk(object): + + def __init__(self, source): + self._cleanup_jobs = [] + self._devices = [] + self.source = source + + def _add_cleanup(self, job, *args): + self._cleanup_jobs.append((job, args)) + + def _losetup(self, fname): + loop = losetup.find_unused_loop_device() + loop.mount(fname) + self._add_cleanup(loop.unmount) + return loop.device + + def _dir_to_disk(self): + raise NotImplementedError + + def cleanup(self): + while len(self._cleanup_jobs): + job, args = self._cleanup_jobs.pop() + job(*args) + + def get_device(self): + sourcedev = self.source + mode = os.stat(self.source).st_mode + if stat.S_ISDIR(mode): + return self._losetup(self._dir_to_disk()) + elif stat.S_ISREG(mode): + sourcedev = self._losetup(self.source) + elif not stat.S_ISBLK(mode): + raise ValueError("Value for self.source is invalid") + + # Take a snapshot and return it to the user + size = blockdev('--getsize', sourcedev) + cowfd, cow = tempfile.mkstemp() + self._add_cleanup(os.unlink, cow) + dd('if=/dev/zero', 'of=%s' % cow, 'count=%d' % (1024*1024))#(int(size)/4)) + cowdev = self._losetup(cow) + + snapshot = uuid.uuid4().hex + tablefd, table = tempfile.mkstemp() + try: + os.write(tablefd, "0 %d snapshot %s %s n 8" % \ + (int(size), sourcedev, cowdev)) + dmsetup('create', snapshot, table) + self._add_cleanup(dmsetup, 'remove', snapshot) + finally: + os.unlink(table) + + new_device = DiskDevice(self, "/dev/mapper/%s" % snapshot) + self._devices.append(new_device) + return new_device + +class DiskDevice(object): + + def __init__(self, disk, device): + self.disk = disk + self.dev = device + self.partitions_mapped = False + self.magic_number = uuid.uuid4().hex + + def list_partitions(self): + output = kpartx("-l", "-p", self.magic_number, self.dev) + return [ "/dev/mapper/%s" % x for x in + re.findall('^\S+', str(output), flags=re.MULTILINE)] + + def mount(self, partition): + if not self.partitions_mapped: + kpartx("-a", "-p", self.magic_number, self.dev) + self.disk._cleanup_jobs.append(kpartx, "-d", "-p", + self.magic_number, self.dev) + self.partitions_mapped = True + + targetfd, target = tempfile.mkdtemp() + try: + mount(dev, partition) + except: + os.rmdir(table) + raise + return target + + def unmount(self, partition): + umount(target) + + mode = os.stat(self.source).st_mode + if stat.S_ISDIR(mode): + os.rmdir(target) + +# vim: set sta sts=4 shiftwidth=4 sw=4 et ai : diff --git a/image_creator/main.py b/image_creator/main.py new file mode 100644 index 0000000..554cdd3 --- /dev/null +++ b/image_creator/main.py @@ -0,0 +1,56 @@ +# Copyright 2011 GRNET S.A. All rights reserved. +# +# Redistribution and use in source and binary forms, with or +# without modification, are permitted provided that the following +# conditions are met: +# +# 1. Redistributions of source code must retain the above +# copyright notice, this list of conditions and the following +# disclaimer. +# +# 2. Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials +# provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS +# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +# The views and conclusions contained in the software and +# documentation are those of the authors and should not be +# interpreted as representing official policies, either expressed +# or implied, of GRNET S.A. + +from image_creator.disk import Disk +import sys +import os + +def main(): + if len(sys.argv) != 3: + sys.exit("Usage: %s " % + os.path.basename(sys.argv[0])) + source = sys.argv[1] + dest = sys.argv[2] + + disk = Disk(source) + try: + dev = disk.get_device() + + finally: + disk.cleanup() + +if __name__ == '__main__': + main() + +# vim: set sta sts=4 shiftwidth=4 sw=4 et ai : + diff --git a/setup.py b/setup.py new file mode 100755 index 0000000..d962e3f --- /dev/null +++ b/setup.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python + +# Copyright 2011 GRNET S.A. All rights reserved. +# +# Redistribution and use in source and binary forms, with or +# without modification, are permitted provided that the following +# conditions are met: +# +# 1. Redistributions of source code must retain the above +# copyright notice, this list of conditions and the following +# disclaimer. +# +# 2. Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following +# disclaimer in the documentation and/or other materials +# provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS +# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED +# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +# The views and conclusions contained in the software and +# documentation are those of the authors and should not be +# interpreted as representing official policies, either expressed +# or implied, of GRNET S.A. + +import image_creator + +from setuptools import setup + + +setup( + name='snf_image_creator', + version=image_creator.__version__, + description='Command line tool for creating images', +# long_description=open('README.rst').read(), + url='https://code.grnet.gr/projects/snf-image-creator', + license='BSD', + packages=['image_creator'], + include_package_data=True, + entry_points={ + 'console_scripts': ['snf-image-creator = image_creator.main:main'] + } +)