Allow image creation from unsupported media
authorNikos Skalkotos <skalkoto@grnet.gr>
Fri, 11 Oct 2013 15:02:30 +0000 (18:02 +0300)
committerNikos Skalkotos <skalkoto@grnet.gr>
Fri, 11 Oct 2013 15:02:30 +0000 (18:02 +0300)
Add a new "Unsupported" os_type class. Images that get created from
unsupported media have the EXCLUDE_ALL_TASKS property enabled.

image_creator/dialog_main.py
image_creator/dialog_menu.py
image_creator/image.py
image_creator/main.py
image_creator/os_type/__init__.py
image_creator/os_type/unsupported.py [new file with mode: 0644]

index 7895287..0586327 100644 (file)
@@ -101,6 +101,25 @@ def create_image(d, media, out, tmp):
                    "image": image,
                    "metadata": metadata}
 
                    "image": image,
                    "metadata": metadata}
 
+        if hasattr(image, "unsupported"):
+
+            session['excluded_tasks'] = [-1]
+            session['task_metadata'] = ["EXCLUDE_ALL_TASKS"]
+
+            msg = "The system on the input media is not supported." \
+                "\n\nReason: %s\n\n" \
+                "We highly recommend not to create an image out of this, " \
+                "since the image won't be cleaned up and you will not be " \
+                "able to configure it during the deployment. Press <YES> if " \
+                "you still want to continue with the image creation process." \
+                % image.unsupported
+
+            if not d.yesno(msg, width=WIDTH, defaultno=1, height=12):
+                main_menu(session)
+
+            d.infobox("Thank you for using snf-image-creator. Bye", width=53)
+            return 0
+
         msg = "snf-image-creator detected a %s system on the input media. " \
               "Would you like to run a wizard to assist you through the " \
               "image creation process?\n\nChoose <Wizard> to run the wizard," \
         msg = "snf-image-creator detected a %s system on the input media. " \
               "Would you like to run a wizard to assist you through the " \
               "image creation process?\n\nChoose <Wizard> to run the wizard," \
index 25fcb6c..ba29ea1 100644 (file)
@@ -583,6 +583,12 @@ def delete_properties(session):
 def exclude_tasks(session):
     """Exclude specific tasks from running during image deployment"""
     d = session['dialog']
 def exclude_tasks(session):
     """Exclude specific tasks from running during image deployment"""
     d = session['dialog']
+    image = session['image']
+
+    if hasattr(image, "unsupported"):
+        d.msgbox("You cannot configure the deployment tasks for an unsupported"
+                 " image.", width=SMALL_WIDTH)
+        return False
 
     index = 0
     displayed_index = 1
 
     index = 0
     displayed_index = 1
index 7eb8ad8..2eb97dd 100644 (file)
@@ -88,11 +88,25 @@ class Image(object):
 
         self.out.output('Inspecting Operating System ...', False)
         roots = self.g.inspect_os()
 
         self.out.output('Inspecting Operating System ...', False)
         roots = self.g.inspect_os()
-        if len(roots) == 0:
-            raise FatalError("No operating system found")
-        if len(roots) > 1:
-            raise FatalError("Multiple operating systems found."
-                             "We only support images with one OS.")
+
+        if len(roots) == 0 or len(roots) > 1:
+            self.root = None
+            self.ostype = "unsupported"
+            self.distro = "unsupported"
+            self.guestfs_device = '/dev/sda'
+            self.size = self.g.blockdev_getsize64(self.guestfs_device)
+            if len(roots) > 1:
+                self.unsupported = "Multiple operating systems found on the " \
+                    "media. We only support images with one OS."
+            else:
+                self.unsupported = \
+                    "Unable to detect any operating system on the media"
+
+            self.meta['UNSUPPORTED'] = "Reason: %s" % self.unsupported
+            self.out.warn('Media is not supported. %s' %
+                          self.meta['UNSUPPORTED'])
+            return
+
         self.root = roots[0]
         self.guestfs_device = self.g.part_to_dev(self.root)
         self.size = self.g.blockdev_getsize64(self.guestfs_device)
         self.root = roots[0]
         self.guestfs_device = self.g.part_to_dev(self.root)
         self.size = self.g.blockdev_getsize64(self.guestfs_device)
@@ -264,6 +278,10 @@ class Image(object):
 
         self.out.output("Shrinking image (this may take a while) ...", False)
 
 
         self.out.output("Shrinking image (this may take a while) ...", False)
 
+        if hasattr(self, "unsupported"):
+            self.out.warn("Unable to shrink unsupported image")
+            return self.size
+
         sector_size = self.g.blockdev_getss(self.guestfs_device)
 
         last_part = None
         sector_size = self.g.blockdev_getss(self.guestfs_device)
 
         last_part = None
index c328146..29ed068 100644 (file)
@@ -140,6 +140,10 @@ def parse_options(input_args):
                       help="register image with the cloud as public",
                       action="store_true")
 
                       help="register image with the cloud as public",
                       action="store_true")
 
+    parser.add_option("--allow-unsupported", dest="allow_unsupported",
+                      help="Proceed with the image creation even if the media "
+                      "is not supported", default=False, action="store_true")
+
     parser.add_option("--tmpdir", dest="tmp", type="string", default=None,
                       help="create large temporary image files under DIR",
                       metavar="DIR")
     parser.add_option("--tmpdir", dest="tmp", type="string", default=None,
                       help="create large temporary image files under DIR",
                       metavar="DIR")
@@ -273,6 +277,14 @@ def image_creator():
 
         image = disk.get_image(snapshot, sysprep_params=options.sysprep_params)
 
 
         image = disk.get_image(snapshot, sysprep_params=options.sysprep_params)
 
+        if hasattr(image, 'unsupported') and not options.allow_unsupported:
+            raise FatalError(
+                "The media seems to be unsupported. If you insist on creating "
+                "an image out of it, use the `--allow-unsupported' option. "
+                "Using this is highly discouraged, since the resulting image "
+                "will not be cleaned up from sensitive data and will not get "
+                "configured during the deployment")
+
         for sysprep in options.disabled_syspreps:
             image.os.disable_sysprep(image.os.get_sysprep_by_name(sysprep))
 
         for sysprep in options.disabled_syspreps:
             image.os.disable_sysprep(image.os.get_sysprep_by_name(sysprep))
 
@@ -298,6 +310,9 @@ def image_creator():
         size = options.shrink and image.shrink() or image.size
         metadata.update(image.meta)
 
         size = options.shrink and image.shrink() or image.size
         metadata.update(image.meta)
 
+        if hasattr(image, 'unsupported'):
+            metadata['EXCLUDE_ALL_TASKS'] = "yes"
+
         # Add command line metadata to the collected ones...
         metadata.update(options.metadata)
 
         # Add command line metadata to the collected ones...
         metadata.update(options.metadata)
 
index 5298569..ff51deb 100644 (file)
@@ -247,12 +247,17 @@ class OSBase(object):
     def do_sysprep(self):
         """Prepare system for image creation."""
 
     def do_sysprep(self):
         """Prepare system for image creation."""
 
+        self.out.output('Preparing system for image creation:')
+
+        if hasattr(self.image, "unsupported"):
+            self.out.warn(
+                "System preparation is disabled for unsupported media")
+            return
+
         try:
             if not self.mount(readonly=False):
                 raise FatalError("Unable to mount the media read-write")
 
         try:
             if not self.mount(readonly=False):
                 raise FatalError("Unable to mount the media read-write")
 
-            self.out.output('Preparing system for image creation:')
-
             enabled = [task for task in self.list_syspreps() if task.enabled]
 
             size = len(enabled)
             enabled = [task for task in self.list_syspreps() if task.enabled]
 
             size = len(enabled)
diff --git a/image_creator/os_type/unsupported.py b/image_creator/os_type/unsupported.py
new file mode 100644 (file)
index 0000000..9b27b7b
--- /dev/null
@@ -0,0 +1,55 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright 2013 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.
+
+"""This module hosts code to handle unknown OSs."""
+
+from image_creator.os_type import OSBase
+
+
+class Unsupported(OSBase):
+    """OS class for unsupported OSs"""
+    def __init__(self, image, **kargs):
+        super(Unsupported, self).__init__(image, **kargs)
+
+    def collect_metadata(self):
+        """Collect metadata about the OS"""
+        self.out.warn("Unable to collect metadata for unsupported media")
+
+    def _do_mount(self, readonly):
+        """Mount partitions in corrent order"""
+        self.out.warn('not supported on this media.')
+        return False
+
+# vim: set sta sts=4 shiftwidth=4 sw=4 et ai :