From aa797ca130c5331e6d40d4be746c3963ec9de111 Mon Sep 17 00:00:00 2001 From: Joar Wandborg Date: Thu, 4 Aug 2011 14:49:12 +0200 Subject: [PATCH] Feature #477 - Cloud Files public storage * mediagoblin.storage is now fully PEP-8 compliant. * mediagoblin.storage:BaseFileStorage precedes CloudFilesStorage * Removed all the cloudfiles-specific options from mediagoblin.ini, now it's in the wiki, http://wiki.mediagoblin.org/ConfigureMediaGoblin#Setting_up_Cloud_Files_public_storage --- mediagoblin.ini | 28 +-------- mediagoblin/storage.py | 140 ++++++++++++++++++++++------------------- 2 files changed, 77 insertions(+), 91 deletions(-) diff --git a/mediagoblin.ini b/mediagoblin.ini index 100e9376..e889646a 100644 --- a/mediagoblin.ini +++ b/mediagoblin.ini @@ -1,33 +1,7 @@ [mediagoblin] -## -# BEGIN CloudFiles public storage -## -# Uncomment the following line and fill in your details to enable Cloud Files -# (or OpenStack Object Storage [Swift]) -# - -# publicstore_storage_class = mediagoblin.storage:CloudFilesStorage -publicstore_cloudfiles_user = user -publicstore_cloudfiles_api_key = 1a2b3c4d5e6f7g8h9i -publicstore_cloudfiles_container = mediagoblin - -# Only applicable if you run MediaGoblin on a Rackspace Cloud Server -# it routes traffic through the internal Rackspace network, this -# means that the bandwith betis free. -publicstore_cloudfiles_use_servicenet = false -## -# END CloudFiles -## - -## -# BEGIN filesystem public storage -## +queuestore_base_dir = %(here)s/user_dev/media/queue publicstore_base_dir = %(here)s/user_dev/media/public publicstore_base_url = /mgoblin_media/ -## -# END -## - -queuestore_base_dir = %(here)s/user_dev/media/queue direct_remote_path = /mgoblin_static/ email_sender_address = "notice@mediagoblin.example.org" diff --git a/mediagoblin/storage.py b/mediagoblin/storage.py index 0e50938f..e449eda3 100644 --- a/mediagoblin/storage.py +++ b/mediagoblin/storage.py @@ -29,11 +29,21 @@ from mediagoblin import util # Errors ######## -class Error(Exception): pass -class InvalidFilepath(Error): pass -class NoWebServing(Error): pass -class NotImplementedError(Error): pass +class Error(Exception): + pass + + +class InvalidFilepath(Error): + pass + + +class NoWebServing(Error): + pass + + +class NotImplementedError(Error): + pass ############################################### @@ -118,7 +128,7 @@ class StorageInterface(object): Eg, if the filename doesn't exist: >>> storage_handler.get_unique_filename(['dir1', 'dir2', 'fname.jpg']) [u'dir1', u'dir2', u'fname.jpg'] - + But if a file does exist, let's get one back with at uuid tacked on: >>> storage_handler.get_unique_filename(['dir1', 'dir2', 'fname.jpg']) [u'dir1', u'dir2', u'd02c3571-dd62-4479-9d62-9e3012dada29-fname.jpg'] @@ -162,61 +172,6 @@ class StorageInterface(object): dest_file.write(source_file.read()) -class CloudFilesStorage(StorageInterface): - def __init__(self, **kwargs): - self.param_container = kwargs.get('cloudfiles_container') - self.param_user = kwargs.get('cloudfiles_user') - self.param_api_key = kwargs.get('cloudfiles_api_key') - self.param_host = kwargs.get('cloudfiles_host') - self.param_use_servicenet = kwargs.get('cloudfiles_use_servicenet') - - if not self.param_host: - print('No CloudFiles host URL specified, defaulting to Rackspace US') - - self.connection = cloudfiles.get_connection( - username=self.param_user, - api_key=self.param_api_key, - servicenet=True if self.param_use_servicenet == 'true' or \ - self.param_use_servicenet == True else False) - - if not self.param_container in [self.connection.get_container(self.param_container)]: - self.container = self.connection.create_container(self.param_container) - self.container.make_public( - ttl=60 * 60 * 2) - else: - self.container = self.connection.get_container(self.param_container) - - def _resolve_filepath(self, filepath): - return '-'.join( - clean_listy_filepath(filepath)) - - def file_exists(self, filepath): - try: - object = self.container.get_object( - self._resolve_filepath(filepath)) - return True - except cloudfiles.errors.NoSuchObject: - return False - - def get_file(self, filepath, mode='r'): - try: - obj = self.container.get_object( - self._resolve_filepath(filepath)) - except cloudfiles.errors.NoSuchObject: - obj = self.container.create_object( - self._resolve_filepath(filepath)) - - return obj - - def delete_file(self, filepath): - # TODO: Also delete unused directories if empty (safely, with - # checks to avoid race conditions). - self.container.delete_object(filepath) - - def file_url(self, filepath): - return self.get_file(filepath).public_uri() - - class BasicFileStorage(StorageInterface): """ Basic local filesystem implementation of storage API @@ -240,7 +195,7 @@ class BasicFileStorage(StorageInterface): """ return os.path.join( self.base_dir, *clean_listy_filepath(filepath)) - + def file_exists(self, filepath): return os.path.exists(self._resolve_filepath(filepath)) @@ -272,6 +227,65 @@ class BasicFileStorage(StorageInterface): return self._resolve_filepath(filepath) +class CloudFilesStorage(StorageInterface): + def __init__(self, **kwargs): + self.param_container = kwargs.get('cloudfiles_container') + self.param_user = kwargs.get('cloudfiles_user') + self.param_api_key = kwargs.get('cloudfiles_api_key') + self.param_host = kwargs.get('cloudfiles_host') + self.param_use_servicenet = kwargs.get('cloudfiles_use_servicenet') + + if not self.param_host: + print('No CloudFiles host URL specified, ' + 'defaulting to Rackspace US') + + self.connection = cloudfiles.get_connection( + username=self.param_user, + api_key=self.param_api_key, + servicenet=True if self.param_use_servicenet == 'true' or \ + self.param_use_servicenet == True else False) + + if not self.param_container == \ + self.connection.get_container(self.param_container): + self.container = self.connection.create_container( + self.param_container) + self.container.make_public( + ttl=60 * 60 * 2) + else: + self.container = self.connection.get_container( + self.param_container) + + def _resolve_filepath(self, filepath): + return '/'.join( + clean_listy_filepath(filepath)) + + def file_exists(self, filepath): + try: + object = self.container.get_object( + self._resolve_filepath(filepath)) + return True + except cloudfiles.errors.NoSuchObject: + return False + + def get_file(self, filepath, mode='r'): + try: + obj = self.container.get_object( + self._resolve_filepath(filepath)) + except cloudfiles.errors.NoSuchObject: + obj = self.container.create_object( + self._resolve_filepath(filepath)) + + return obj + + def delete_file(self, filepath): + # TODO: Also delete unused directories if empty (safely, with + # checks to avoid race conditions). + self.container.delete_object(filepath) + + def file_url(self, filepath): + return self.get_file(filepath).public_uri() + + ########### # Utilities ########### @@ -339,7 +353,7 @@ def storage_system_from_config(paste_config, storage_prefix): for key, value in paste_config.iteritems() if prefix_re.match(key)]) - if config_params.has_key('storage_class'): + if 'storage_class' in config_params: storage_class = config_params['storage_class'] config_params.pop('storage_class') else: @@ -347,5 +361,3 @@ def storage_system_from_config(paste_config, storage_prefix): storage_class = util.import_component(storage_class) return storage_class(**config_params) - - -- 2.25.1