This repository has been archived on 2020-03-24. You can view files and clone it, but cannot push or open issues or pull requests.
quay/storage/__init__.py

144 lines
4.2 KiB
Python
Raw Normal View History

2013-09-25 21:50:03 +00:00
import contextlib
import tempfile
__all__ = ['load']
class Storage(object):
"""Storage is organized as follow:
$ROOT/images/<image_id>/json
$ROOT/images/<image_id>/layer
$ROOT/repositories/<namespace>/<repository_name>/<tag_name>
"""
# Useful if we want to change those locations later without rewriting
# the code which uses Storage
repositories = 'repositories'
images = 'images'
# Set the IO buffer to 64kB
buffer_size = 64 * 1024
#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_json_path(self, namespace, repository, image_id):
return '{0}/{1}/{2}/{3}/json'.format(self.images, namespace,
repository, image_id)
2013-09-25 21:50:03 +00:00
def image_mark_path(self, namespace, repository, image_id):
return '{0}/{1}/{2}/{3}/_inprogress'.format(self.images, namespace,
repository, image_id)
2013-09-25 21:50:03 +00:00
def image_checksum_path(self, namespace, repository, image_id):
return '{0}/{1}/{2}/{3}/_checksum'.format(self.images, namespace,
repository, image_id)
2013-09-25 21:50:03 +00:00
def image_layer_path(self, namespace, repository, image_id):
return '{0}/{1}/{2}/{3}/layer'.format(self.images, namespace,
repository, image_id)
2013-09-25 21:50:03 +00:00
def image_ancestry_path(self, namespace, repository, image_id):
return '{0}/{1}/{2}/{3}/ancestry'.format(self.images, namespace,
repository, image_id)
2013-09-25 21:50:03 +00:00
def tag_path(self, namespace, repository, tagname=None):
if not tagname:
return '{0}/{1}/{2}'.format(self.repositories,
namespace,
repository)
return '{0}/{1}/{2}/tag_{3}'.format(self.repositories,
namespace,
repository,
tagname)
def index_images_path(self, namespace, repository):
return '{0}/{1}/{2}/_index_images'.format(self.repositories,
namespace,
repository)
def get_content(self, path):
raise NotImplementedError
def put_content(self, path, content):
raise NotImplementedError
def stream_read(self, path):
raise NotImplementedError
def stream_write(self, path, fp):
raise NotImplementedError
def list_directory(self, path=None):
raise NotImplementedError
def exists(self, path):
raise NotImplementedError
def remove(self, path):
raise NotImplementedError
def get_size(self, path):
raise NotImplementedError
@contextlib.contextmanager
def store_stream(stream):
"""Stores the entire stream to a temporary file."""
tmpf = tempfile.TemporaryFile()
while True:
try:
buf = stream.read(4096)
if not buf:
break
tmpf.write(buf)
except IOError:
break
tmpf.seek(0)
yield tmpf
tmpf.close()
def temp_store_handler():
tmpf = tempfile.TemporaryFile()
def fn(buf):
try:
tmpf.write(buf)
except IOError:
pass
return tmpf, fn
from local import LocalStorage
from s3 import S3Storage
_storage = {}
def load(kind=None):
"""Returns the right storage class according to the configuration."""
global _storage
# TODO hard code to local for now
kind = 'local'
# if not kind:
# kind = cfg.storage.lower()
if kind in _storage:
return _storage[kind]
if kind == 's3':
store = S3Storage('/registry', 'access_key', 'secret_key', 'bucket')
elif kind == 'local':
store = LocalStorage('/tmp/registry')
else:
raise ValueError('Not supported storage \'{0}\''.format(kind))
_storage[kind] = store
return store