# vim: tabstop=4 shiftwidth=4 softtabstop=4 # Copyright 2012 United States Government as represented by the # Administrator of the National Aeronautics and Space Administration. # All Rights Reserved. # # Copyright 2012 Nebula, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import logging import cloudfiles from django.conf import settings from django.utils.translation import ugettext as _ from horizon import exceptions from horizon.api.base import url_for LOG = logging.getLogger(__name__) class SwiftAuthentication(object): """ Auth container in the format CloudFiles expects. """ def __init__(self, storage_url, auth_token): self.storage_url = storage_url self.auth_token = auth_token def authenticate(self): return (self.storage_url, '', self.auth_token) def swift_api(request): endpoint = url_for(request, 'object-store') LOG.debug('Swift connection created using token "%s" and url "%s"' % (request.session['token'], endpoint)) auth = SwiftAuthentication(endpoint, request.session['token']) return cloudfiles.get_connection(auth=auth) def swift_container_exists(request, container_name): try: swift_api(request).get_container(container_name) return True except cloudfiles.errors.NoSuchContainer: return False def swift_object_exists(request, container_name, object_name): container = swift_api(request).get_container(container_name) try: container.get_object(object_name) return True except cloudfiles.errors.NoSuchObject: return False def swift_get_containers(request, marker=None): limit = getattr(settings, 'API_RESULT_LIMIT', 1000) containers = swift_api(request).get_all_containers(limit=limit + 1, marker=marker) if(len(containers) > limit): return (containers[0:-1], True) else: return (containers, False) def swift_create_container(request, name): if swift_container_exists(request, name): raise exceptions.AlreadyExists(name, 'container') return swift_api(request).create_container(name) def swift_delete_container(request, name): swift_api(request).delete_container(name) def swift_get_objects(request, container_name, prefix=None, path=None, marker=None): limit = getattr(settings, 'API_RESULT_LIMIT', 1000) container = swift_api(request).get_container(container_name) objects = container.get_objects(prefix=prefix, marker=marker, limit=limit + 1, delimiter="/", path=path) if(len(objects) > limit): return (objects[0:-1], True) else: return (objects, False) def swift_filter_objects(request, filter_string, container_name, prefix=None, path=None, marker=None): #FIXME(kewu): Cloudfiles currently has no filtering API, thus the marker #parameter here won't actually help the pagination. For now I am just #getting the largest number of objects from a container and filtering based #on those objects. limit = 10000 container = swift_api(request).get_container(container_name) objects = container.get_objects(prefix=prefix, marker=marker, limit=limit, delimiter="/", path=path) filter_string_list = filter_string.lower().strip().split(' ') return filter(lambda obj: any([ obj.content_type != "application/directory" and wildcard_search(obj.name.lower(), q) for q in filter_string_list if q != '' ]), objects) def wildcard_search(string, q): q_list = q.split('*') if all(map(lambda x: x == '', q_list)): return True elif q_list[0] not in string: return False else: if q_list[0] == '': tail = string else: head, delimiter, tail = string.partition(q_list[0]) return wildcard_search(tail, '*'.join(q_list[1:])) def swift_copy_object(request, orig_container_name, orig_object_name, new_container_name, new_object_name): try: # FIXME(gabriel): Cloudfiles currently fails at unicode in the # copy_to method, so to provide a better experience we check for # unicode here and pre-empt with an error message rather than # letting the call fail. str(orig_container_name) str(orig_object_name) str(new_container_name) str(new_object_name) except UnicodeEncodeError: raise exceptions.HorizonException(_("Unicode is not currently " "supported for object copy.")) container = swift_api(request).get_container(orig_container_name) if swift_object_exists(request, new_container_name, new_object_name): raise exceptions.AlreadyExists(new_object_name, 'object') orig_obj = container.get_object(orig_object_name) return orig_obj.copy_to(new_container_name, new_object_name) def swift_create_subfolder(request, container_name, folder_name): container = swift_api(request).get_container(container_name) obj = container.create_object(folder_name) obj.headers = {'content-type': 'application/directory', 'content-length': 0} obj.send('') obj.sync_metadata() return obj def swift_upload_object(request, container_name, object_name, object_file): container = swift_api(request).get_container(container_name) obj = container.create_object(object_name) obj.send(object_file) return obj def swift_delete_object(request, container_name, object_name): container = swift_api(request).get_container(container_name) container.delete_object(object_name) def swift_get_object(request, container_name, object_name): container = swift_api(request).get_container(container_name) return container.get_object(object_name) def swift_get_object_data(request, container_name, object_name): container = swift_api(request).get_container(container_name) return container.get_object(object_name).stream()