diff --git a/data/database.py b/data/database.py index 86a797bed..0f46ff9f6 100644 --- a/data/database.py +++ b/data/database.py @@ -186,7 +186,9 @@ class Image(BaseModel): image_size = BigIntegerField(null=True) # '/' separated list of ancestory ids, e.g. /1/2/6/7/10/ - ancestors = CharField(index=True, default='/', max_length=64535) + ancestors = CharField(index=True, default='/', max_length=64535, null=True) + + storage = ForeignKeyField(ImageStorage, index=True, null=True) class Meta: database = db @@ -196,6 +198,18 @@ class Image(BaseModel): ) +class ImageStorage(BaseModel): + storage_uuid = CharField(default=uuid_generator) + checksum = CharField(null=True) + created = DateTimeField(null=True) + comment = TextField(null=True) + command = TextField(null=True) + image_size = BigIntegerField(null=True) + + # '/' separated list of ancestory ids, e.g. /1/2/6/7/10/ + ancestors = CharField(index=True, default='/', max_length=64535) + + class RepositoryTag(BaseModel): name = CharField() image = ForeignKeyField(Image) diff --git a/data/model.py b/data/model.py index f6dd75965..524245db9 100644 --- a/data/model.py +++ b/data/model.py @@ -772,10 +772,15 @@ def get_repository(namespace_name, repository_name): def get_repo_image(namespace_name, repository_name, image_id): - joined = Image.select().join(Repository) - query = joined.where(Repository.name == repository_name, - Repository.namespace == namespace_name, - Image.docker_image_id == image_id).limit(1) + query = (Image + .select() + .join(Repository) + .switch(Image) + .join(ImageStorage, JOIN_LEFT_OUTER) + .where(Repository.name == repository_name, + Repository.namespace == namespace_name, + Image.docker_image_id == image_id) + .limit(1)) result = list(query) if not result: return None diff --git a/storage/basestorage.py b/storage/basestorage.py index 1217e3c2b..474e53894 100644 --- a/storage/basestorage.py +++ b/storage/basestorage.py @@ -13,6 +13,7 @@ class Storage(object): # the code which uses Storage repositories = 'repositories' images = 'images' + shared_images = 'sharedimages' # Set the IO buffer to 64kB buffer_size = 64 * 1024 @@ -28,46 +29,45 @@ class Storage(object): return tmpf, fn - #FIXME(samalba): Move all path resolver in each module (out of the base) - def images_list_path(self, namespace, repository): - return '{0}/{1}/{2}/_images_list'.format(self.repositories, - namespace, - repository) + def image_path(self, namespace, repository, image_id, storage_uuid): + if storage_uuid: + return '{0}/{1}/'.format(self.shared_images, storage_uuid) + else: + return '{0}/{1}/{2}/{3}/'.format(self.images, namespace, repository, + image_id) - def image_path(self, namespace, repository, image_id): - return '{0}/{1}/{2}/{3}/'.format(self.images, namespace, repository, - image_id) + def image_json_path(self, namespace, repository, image_id, storage_uuid): + base_path = self.image_path(namespace, repository, image_id, storage_uuid) + return '{0}/json'.format(base_path) - def image_json_path(self, namespace, repository, image_id): - return '{0}/{1}/{2}/{3}/json'.format(self.images, namespace, - repository, image_id) + def image_mark_path(self, namespace, repository, image_id, storage_uuid): + base_path = self.image_path(namespace, repository, image_id, storage_uuid) + return '{0}/_inprogress'.format(base_path) - def image_mark_path(self, namespace, repository, image_id): - return '{0}/{1}/{2}/{3}/_inprogress'.format(self.images, namespace, - repository, image_id) + def image_checksum_path(self, namespace, repository, image_id, storage_uuid): + base_path = self.image_path(namespace, repository, image_id, storage_uuid) + return '{0}/_checksum'.format(base_path) - def image_checksum_path(self, namespace, repository, image_id): - return '{0}/{1}/{2}/{3}/_checksum'.format(self.images, namespace, - repository, image_id) + def image_layer_path(self, namespace, repository, image_id, storage_uuid): + base_path = self.image_path(namespace, repository, image_id, storage_uuid) + return '{0}/layer'.format(base_path) - def image_layer_path(self, namespace, repository, image_id): - return '{0}/{1}/{2}/{3}/layer'.format(self.images, namespace, - repository, image_id) - - def image_ancestry_path(self, namespace, repository, image_id): - return '{0}/{1}/{2}/{3}/ancestry'.format(self.images, namespace, - repository, image_id) + def image_ancestry_path(self, namespace, repository, image_id, storage_uuid): + base_path = self.image_path(namespace, repository, image_id, storage_uuid) + return '{0}/ancestry'.format(base_path) def repository_namespace_path(self, namespace, repository): return '{0}/{1}/{2}/'.format(self.images, namespace, repository) - def image_file_trie_path(self, namespace, repository, image_id): - return '{0}/{1}/{2}/{3}/files.trie'.format(self.images, namespace, - repository, image_id) + def image_file_trie_path(self, namespace, repository, image_id, + storage_uuid): + base_path = self.image_path(namespace, repository, image_id, storage_uuid) + return '{0}/files.trie'.format(base_path) - def image_file_diffs_path(self, namespace, repository, image_id): - return '{0}/{1}/{2}/{3}/diffs.json'.format(self.images, namespace, - repository, image_id) + def image_file_diffs_path(self, namespace, repository, image_id, + storage_uuid): + base_path = self.image_path(namespace, repository, image_id, storage_uuid) + return '{0}/diffs.json'.format(base_path) def get_direct_download_url(self, path, expires_in=60): return None