--- /dev/null
+# 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'
--- /dev/null
+#!/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 :
--- /dev/null
+# 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 <source> <output_file>" %
+ 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 :
+
--- /dev/null
+#!/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']
+ }
+)