diff --git a/circle/storage/migrations/0015_set_is_ready_to_base_images.py b/circle/storage/migrations/0015_set_is_ready_to_base_images.py
new file mode 100644
index 0000000..2c4af52
--- /dev/null
+++ b/circle/storage/migrations/0015_set_is_ready_to_base_images.py
@@ -0,0 +1,57 @@
+# -*- coding: utf-8 -*-
+from south.utils import datetime_utils as datetime
+from south.db import db
+from south.v2 import DataMigration
+from django.db import models
+
+import logging
+
+logging.basicConfig(filename='/var/tmp/0015_disk_migration.log',level=logging.INFO)
+logger = logging.getLogger()
+
+class Migration(DataMigration):
+
+    def forwards(self, orm):
+        "Write your forwards methods here."
+        # Note: Don't use "from appname.models import ModelName".
+        # Use orm.ModelName to refer to models in this application,
+        # and orm['appname.ModelName'] for models in other applications.
+        disks = orm.Disk
+        for disk in disks.objects.all():
+            if disk.base is None and disk.destroyed is None:
+                logger.info("Set disk %s (%s) with filename: %s to ready.",
+                            disk.name, disk.pk, disk.filename)
+                disk.is_ready = True
+                disk.save()
+
+
+    def backwards(self, orm):
+        "Write your backwards methods here."
+
+    models = {
+        u'storage.datastore': {
+            'Meta': {'ordering': "[u'name']", 'object_name': 'DataStore'},
+            'hostname': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '40'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'name': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '100'}),
+            'path': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '200'})
+        },
+        u'storage.disk': {
+            'Meta': {'ordering': "[u'name']", 'object_name': 'Disk'},
+            'base': ('django.db.models.fields.related.ForeignKey', [], {'blank': 'True', 'related_name': "u'derivatives'", 'null': 'True', 'to': u"orm['storage.Disk']"}),
+            'created': ('model_utils.fields.AutoCreatedField', [], {'default': 'datetime.datetime.now'}),
+            'datastore': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['storage.DataStore']"}),
+            'destroyed': ('django.db.models.fields.DateTimeField', [], {'default': 'None', 'null': 'True', 'blank': 'True'}),
+            'dev_num': ('django.db.models.fields.CharField', [], {'default': "u'a'", 'max_length': '1'}),
+            'filename': ('django.db.models.fields.CharField', [], {'unique': 'True', 'max_length': '256'}),
+            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
+            'is_ready': ('django.db.models.fields.BooleanField', [], {'default': 'False'}),
+            'modified': ('model_utils.fields.AutoLastModifiedField', [], {'default': 'datetime.datetime.now'}),
+            'name': ('django.db.models.fields.CharField', [], {'max_length': '100', 'blank': 'True'}),
+            'size': ('sizefield.models.FileSizeField', [], {'default': 'None', 'null': 'True'}),
+            'type': ('django.db.models.fields.CharField', [], {'max_length': '10'})
+        }
+    }
+
+    complete_apps = ['storage']
+    symmetrical = True
diff --git a/circle/storage/models.py b/circle/storage/models.py
index a4d7fe6..3600b7a 100644
--- a/circle/storage/models.py
+++ b/circle/storage/models.py
@@ -27,13 +27,13 @@ from celery.contrib.abortable import AbortableAsyncResult
 from django.db.models import (Model, BooleanField, CharField, DateTimeField,
                               ForeignKey)
 from django.utils import timezone
-from django.utils.translation import ugettext_lazy as _
+from django.utils.translation import ugettext_lazy as _, ugettext_noop
 from model_utils.models import TimeStampedModel
 from sizefield.models import FileSizeField
 
 from .tasks import local_tasks, storage_tasks
 from celery.exceptions import TimeoutError
-from common.models import WorkerNotFound
+from common.models import WorkerNotFound, HumanReadableException
 
 logger = logging.getLogger(__name__)
 
@@ -104,43 +104,73 @@ class Disk(TimeStampedModel):
             ('create_empty_disk', _('Can create an empty disk.')),
             ('download_disk', _('Can download a disk.')))
 
-    class WrongDiskTypeError(Exception):
-
-        def __init__(self, type, message=None):
-            if message is None:
-                message = ("Operation can't be invoked on a disk of type '%s'."
-                           % type)
-
-            Exception.__init__(self, message)
-
-            self.type = type
-
-    class DiskInUseError(Exception):
-
-        def __init__(self, disk, message=None):
-            if message is None:
-                message = ("The requested operation can't be performed on "
-                           "disk '%s (%s)' because it is in use." %
-                           (disk.name, disk.filename))
-
-            Exception.__init__(self, message)
-
-            self.disk = disk
-
-    class DiskIsNotReady(Exception):
-
-        """ Exception for operations that need a deployed disk.
-        """
-
-        def __init__(self, disk, message=None):
-            if message is None:
-                message = ("The requested operation can't be performed on "
-                           "disk '%s (%s)' because it has never been"
-                           "deployed." % (disk.name, disk.filename))
-
-            Exception.__init__(self, message)
-
-            self.disk = disk
+    class DiskError(HumanReadableException):
+        admin_message = None
+
+        def __init__(self, disk, params=None, level=None, **kwargs):
+            kwargs.update(params or {})
+            self.disc = kwargs["disk"] = disk
+            super(Disk.DiskError, self).__init__(
+                level, self.message, self.admin_message or self.message,
+                kwargs)
+
+    class WrongDiskTypeError(DiskError):
+        message = ugettext_noop("Operation can't be invoked on disk "
+                                "'%(name)s' of type '%(type)s'.")
+
+        admin_message = ugettext_noop(
+            "Operation can't be invoked on disk "
+            "'%(name)s' (%(pk)s) of type '%(type)s'.")
+
+        def __init__(self, disk, params=None, **kwargs):
+            super(Disk.WrongDiskTypeError, self).__init__(
+                disk, params, type=disk.type, name=disk.name, pk=disk.pk)
+
+    class DiskInUseError(DiskError):
+        message = ugettext_noop(
+            "The requested operation can't be performed on "
+            "disk '%(name)s' because it is in use.")
+
+        admin_message = ugettext_noop(
+            "The requested operation can't be performed on "
+            "disk '%(name)s' (%(pk)s) because it is in use.")
+
+        def __init__(self, disk, params=None, **kwargs):
+            super(Disk.DiskInUseError, self).__init__(
+                disk, params, name=disk.name, pk=disk.pk)
+
+    class DiskIsNotReady(DiskError):
+        message = ugettext_noop(
+            "The requested operation can't be performed on "
+            "disk '%(name)s' because it has never been deployed.")
+
+        admin_message = ugettext_noop(
+            "The requested operation can't be performed on "
+            "disk '%(name)s' (%(pk)s) [%(filename)s] because it has never been"
+            "deployed.")
+
+        def __init__(self, disk, params=None, **kwargs):
+            super(Disk.DiskIsNotReady, self).__init__(
+                disk, params, name=disk.name, pk=disk.pk,
+                filename=disk.filename)
+
+    class DiskBaseIsNotReady(DiskError):
+        message = ugettext_noop(
+            "The requested operation can't be performed on "
+            "disk '%(name)s' because its base has never been deployed.")
+
+        admin_message = ugettext_noop(
+            "The requested operation can't be performed on "
+            "disk '%(name)s' (%(pk)s) [%(filename)s] because its base "
+            "'%(b_name)s' (%(b_pk)s) [%(b_filename)s] has never been"
+            "deployed.")
+
+        def __init__(self, disk, params=None, **kwargs):
+            base = kwargs.get('base')
+            super(Disk.DiskBaseIsNotReady, self).__init__(
+                disk, params, name=disk.name, pk=disk.pk,
+                filename=disk.filename, b_name=base.name,
+                b_pk=base.pk, b_filename=base.filename)
 
     @property
     def path(self):
@@ -240,7 +270,7 @@ class Disk(TimeStampedModel):
         }
 
         if self.type not in type_mapping.keys():
-            raise self.WrongDiskTypeError(self.type)
+            raise self.WrongDiskTypeError(self)
 
         new_type = type_mapping[self.type]
 
@@ -313,6 +343,8 @@ class Disk(TimeStampedModel):
 
         if self.is_ready:
             return True
+        if self.base and not self.base.is_ready:
+            raise self.DiskBaseIsNotReady(self, base=self.base)
         queue_name = self.get_remote_queue_name('storage', priority="fast")
         disk_desc = self.get_disk_desc()
         if self.base is not None:
@@ -417,7 +449,7 @@ class Disk(TimeStampedModel):
             'iso': ("iso", self),
         }
         if self.type not in mapping.keys():
-            raise self.WrongDiskTypeError(self.type)
+            raise self.WrongDiskTypeError(self)
 
         if self.is_in_use:
             raise self.DiskInUseError(self)
@@ -433,7 +465,7 @@ class Disk(TimeStampedModel):
         disk = Disk.create(datastore=self.datastore,
                            base=new_base,
                            name=self.name, size=self.size,
-                           type=new_type)
+                           type=new_type, dev_num=self.dev_num)
 
         queue_name = self.get_remote_queue_name("storage", priority="slow")
         remote = storage_tasks.merge.apply_async(kwargs={
@@ -450,4 +482,6 @@ class Disk(TimeStampedModel):
                     AbortableAsyncResult(remote.id).abort()
                     disk.destroy()
                     raise Exception("Save as aborted by use.")
+        disk.is_ready = True
+        disk.save()
         return disk