def test_storlet_acl_get_success(self): headers = {'X-Run-Storlet': self.storlet_name} headers.update(self.additional_headers) exc_pattern = '^.*403 Forbidden.*$' with self.assertRaisesRegexp(ClientException, exc_pattern): swift_client.get_object(self.member_url, self.member_token, self.container, 'test_object', headers=headers) headers = { 'X-Storlet-Container-Read': self.conf.member_user, 'X-Storlet-Name': self.storlet_name } swift_client.post_container(self.url, self.token, self.container, headers) swift_client.head_container(self.url, self.token, self.container) headers = {'X-Run-Storlet': self.storlet_name} headers.update(self.additional_headers) resp_dict = dict() swift_client.get_object(self.member_url, self.member_token, self.container, 'test_object', response_dict=resp_dict, headers=headers) self.assertEqual(200, resp_dict['status'])
def test_symlink_target(self): if 'symlink' not in self.cluster_info: raise unittest.SkipTest("Symlink not enabled in proxy; can't test " "symlink to reserved name") int_client = self.make_internal_client() # create link container first, ensure account gets created too client.put_container(self.url, self.token, 'c1') # Create reserve named container tgt_cont = get_reserved_name('container-%s' % uuid4()) int_client.create_container(self.account, tgt_cont) # sanity, user can't get to reserved name with self.assertRaises(ClientException) as cm: client.head_container(self.url, self.token, tgt_cont) self.assertEqual(412, cm.exception.http_status) tgt_obj = get_reserved_name('obj-%s' % uuid4()) int_client.upload_object(BytesIO(b'target object'), self.account, tgt_cont, tgt_obj) metadata = int_client.get_object_metadata(self.account, tgt_cont, tgt_obj) etag = metadata['etag'] # users can write a dynamic symlink that targets a reserved # name object client.put_object(self.url, self.token, 'c1', 'symlink', headers={ 'X-Symlink-Target': '%s/%s' % (tgt_cont, tgt_obj), 'Content-Type': 'application/symlink', }) # but can't read the symlink with self.assertRaises(ClientException) as cm: client.get_object(self.url, self.token, 'c1', 'symlink') self.assertEqual(412, cm.exception.http_status) # user's can't create static symlink to reserved name with self.assertRaises(ClientException) as cm: client.put_object(self.url, self.token, 'c1', 'static-symlink', headers={ 'X-Symlink-Target': '%s/%s' % (tgt_cont, tgt_obj), 'X-Symlink-Target-Etag': etag, 'Content-Type': 'application/symlink', }) self.assertEqual(412, cm.exception.http_status) # clean-up client.delete_object(self.url, self.token, 'c1', 'symlink') int_client.delete_object(self.account, tgt_cont, tgt_obj) int_client.delete_container(self.account, tgt_cont)
def test_storlet_acl_get_success(self): headers = {'X-Run-Storlet': self.storlet_name} headers.update(self.additional_headers) exc_pattern = '^.*403 Forbidden.*$' with self.assertRaisesRegexp(ClientException, exc_pattern): swift_client.get_object(self.member_url, self.member_token, 'myobjects', 'test_object', headers=headers) headers = {'X-Storlet-Container-Read': self.conf.member_user, 'X-Storlet-Name': self.storlet_name} swift_client.post_container(self.url, self.token, 'myobjects', headers) swift_client.head_container(self.url, self.token, 'myobjects') headers = {'X-Run-Storlet': self.storlet_name} headers.update(self.additional_headers) resp_dict = dict() swift_client.get_object(self.member_url, self.member_token, 'myobjects', 'test_object', response_dict=resp_dict, headers=headers) self.assertEqual(resp_dict['status'], 200)
def test_server_error(self): body = "c" * 60 c.http_connection = self.fake_http_connection(500, body=body) self.assertRaises(c.ClientException, c.head_container, "http://www.test.com", "asdf", "asdf") try: c.head_container("http://www.test.com", "asdf", "asdf") except c.ClientException as e: self.assertEqual(e.http_response_content, body)
def getMember(self, name): try: client.head_container(self.storage_url, self.auth_token, container=name, http_conn=self.http_connection) return ObjectCollection(name, self.environ, path=self.path) except client.ClientException as ex: if '404' in ex: raise dav_error.DAVError(dav_error.HTTP_NOT_FOUND)
def test_server_error(self): body = 'c' * 60 c.http_connection = self.fake_http_connection(500, body=body) self.assertRaises(c.ClientException, c.head_container, 'http://www.test.com', 'asdf', 'asdf', ) try: c.head_container('http://www.test.com', 'asdf', 'asdf') except c.ClientException as e: self.assertEqual(e.http_response_content, body)
def test_server_error(self): body = 'c' * 60 c.http_connection = self.fake_http_connection(500, body=body) self.assertRaises(c.ClientException, c.head_container, 'http://www.test.com', 'asdf', 'asdf', ) try: c.head_container('http://www.test.com', 'asdf', 'asdf') except c.ClientException as e: self.assertEquals(e.http_response_content, body)
def create_thumbnail(request, account, original_container_name, container, objectname): """ Creates a thumbnail for an image. """ storage_url = request.session.get('storage_url', '') auth_token = request.session.get('auth_token', '') try: client.head_container(storage_url, auth_token, account) except client.ClientException: try: client.put_container( storage_url, auth_token, account) except client.ClientException as e: logger.error("Cannot put container %s. Error: %s " % (container, str(e))) return None try: headers, content = client.get_object( storage_url, auth_token, container, objectname) im = Image.open(StringIO(content)) im.thumbnail(settings.THUMBNAIL_SIZE, Image.ANTIALIAS) output = StringIO() mimetype = headers['content-type'].split('/')[-1] im.save(output, format=mimetype) content = output.getvalue() headers = {'X-Delete-After': settings.THUMBNAIL_DURABILITY} try: client.put_object( storage_url, auth_token, account, "%s_%s" % (original_container_name, objectname), content, headers=headers) except client.ClientException as e: logger.error("Cannot create thumbnail for image %s." "Could not put thumbnail to storage: %s" % (objectname, str(e))) output.close() except client.ClientException as e: logger.error("Cannot create thumbnail for image %s." "Could not retrieve the image from storage: %s" % (objectname, str(e))) except IOError as e: logger.error("Cannot create thumbnail for image %s." "An IOError occured: %s" % (objectname, e.strerror))
def test_simple_crud(self): int_client = self.make_internal_client() # Create reserve named container user_cont = 'container-%s' % uuid4() reserved_cont = get_reserved_name('container-%s' % uuid4()) client.put_container(self.url, self.token, user_cont) int_client.create_container(self.account, reserved_cont) # Check that we can list both reserved and non-reserved containers self.assertEqual( [reserved_cont, user_cont], [c['name'] for c in int_client.iter_containers(self.account)]) # sanity, user can't get to reserved name with self.assertRaises(ClientException) as cm: client.head_container(self.url, self.token, reserved_cont) self.assertEqual(412, cm.exception.http_status) user_obj = 'obj-%s' % uuid4() reserved_obj = get_reserved_name('obj-%s' % uuid4()) # InternalClient can write & read reserved names fine int_client.upload_object(BytesIO(b'data'), self.account, reserved_cont, reserved_obj) int_client.get_object_metadata(self.account, reserved_cont, reserved_obj) _, _, app_iter = int_client.get_object(self.account, reserved_cont, reserved_obj) self.assertEqual(b''.join(app_iter), b'data') self.assertEqual([reserved_obj], [ o['name'] for o in int_client.iter_objects(self.account, reserved_cont) ]) # But reserved objects must be in reserved containers, and # user objects must be in user containers (at least for now) int_client.upload_object(BytesIO(b'data'), self.account, reserved_cont, user_obj, acceptable_statuses=(400, )) int_client.upload_object(BytesIO(b'data'), self.account, user_cont, reserved_obj, acceptable_statuses=(400, )) # Make sure we can clean up, too int_client.delete_object(self.account, reserved_cont, reserved_obj) int_client.delete_container(self.account, reserved_cont)
def wrapper(*args, **kw): storage_url = args[0].session.get('storage_url', '') auth_token = args[0].session.get('auth_token', '') username = args[0].session.get('username', '') password = args[0].session.get('password', '') # If the following variables are available, attempt to get an # auth token if (storage_url and auth_token and username and password): # If the user has no role, head the container to valid the token if args[0].session.get('norole'): storage_url = args[0].session.get('default_storage_url', '') auth_token = args[0].session.get('default_auth_token', '') #Attempt to get a new auth token try: client.head_container( storage_url, auth_token, args[0].session.get('user')) return fn(*args, **kw) except: # Failure to get an auth token, tell the user the session # has expiredself. messages.error(args[0], _("Session expired.")) # A regular user's token is validated by heading the account. else: try: client.head_account(storage_url, auth_token) return fn(*args, **kw) except: #Attempt to get a new auth token try: auth_version = settings.SWIFT_AUTH_VERSION or 1 (storage_url, auth_token) = client.get_auth( settings.SWIFT_AUTH_URL, username, password, auth_version=auth_version) args[0].session['auth_token'] = auth_token args[0].session['storage_url'] = storage_url return fn(*args, **kw) except: # Failure to get an auth token, tell the user the # session has expired. messages.error(args[0], _("Session expired.")) return redirect(swiftbrowser.views.login)
def get_container_metadata(self, swift_url, swift_container): swift_connection = swift.HTTPConnection(url=swift_url, insecure=True) return swift.head_container(swift_url, self.keystone.get_token('id'), swift_container, http_conn=(swift_connection.parsed_url, swift_connection))
def toggle_public(request, container): """ Sets/unsets '.r:*,.rlistings' container read ACL """ storage_url = request.session.get('storage_url', '') auth_token = request.session.get('auth_token', '') try: meta = client.head_container(storage_url, auth_token, container) except client.ClientException: traceback.print_exc() messages.add_message(request, messages.ERROR, _("Access denied.")) return redirect(containerview) read_acl = meta.get('x-container-read', '') if '.rlistings' and '.r:*' in read_acl: read_acl = read_acl.replace('.r:*', '') read_acl = read_acl.replace('.rlistings', '') read_acl = read_acl.replace(',,', ',') else: read_acl += '.r:*,.rlistings' headers = {'X-Container-Read': read_acl, } try: client.post_container(storage_url, auth_token, container, headers) except client.ClientException: traceback.print_exc() messages.add_message(request, messages.ERROR, _("Access denied.")) return redirect(objectview, container=container)
def toggle_public(request, container): """ Sets/unsets '.r:*,.rlistings' container read ACL """ storage_url = request.session.get('storage_url', '') auth_token = request.session.get('auth_token', '') try: meta = client.head_container(storage_url, auth_token, container) except client.ClientException: messages.add_message(request, messages.ERROR, _("Access denied.")) return redirect(containerview) read_acl = meta.get('x-container-read', '') if '.rlistings' and '.r:*' in read_acl: read_acl = read_acl.replace('.r:*', '') read_acl = read_acl.replace('.rlistings', '') read_acl = read_acl.replace(',,', ',') else: read_acl += '.r:*,.rlistings' headers = { 'X-Container-Read': read_acl, } try: client.post_container(storage_url, auth_token, container, headers) except client.ClientException: messages.add_message(request, messages.ERROR, _("Access denied.")) return redirect(objectview, container=container)
def object_versioning(request, container, prefix=None): storage_url = get_endpoint(request, 'adminURL') auth_token = get_token_id(request) public_url = get_endpoint(request, 'publicURL') + '/' + container http_conn = client.http_connection(storage_url, insecure=settings.SWIFT_INSECURE) objects = [] page = request.GET.get('page', 1) if request.method == 'GET': headers = client.head_container(storage_url, auth_token, container, http_conn=http_conn) version_location = headers.get('x-versions-location', None) if version_location: try: _, objects = client.get_container(storage_url, auth_token, version_location, prefix=prefix, delimiter='/', http_conn=http_conn) except client.ClientException: pass prefixes = prefix_list(prefix) object_list = pseudofolder_object_list(objects, prefix, public_url) context = utils.update_default_context(request, { 'container': container, 'objects': utils.generic_pagination(object_list, page), 'version_location': version_location, 'prefix': prefix, 'prefixes': prefixes, }) return render_to_response('container_versioning.html', dictionary=context, context_instance=RequestContext(request)) if request.method == 'POST': action = request.POST.get('action', None) if action == 'enable': enable_versioning(request, container) actionlog.log(request.user.username, "enable", 'Versioning. Container: %s' % container) elif action == 'disable': disable_versioning(request, container) actionlog.log(request.user.username, "disable", 'Versioning. Container: %s' % container) else: messages.add_message(request, messages.ERROR, ugettext('Action is required.')) return redirect(object_versioning, container=container)
def get_acls(storage_url, auth_token, container, http_conn): """ Returns ACLs of given container. """ acls = client.head_container(storage_url, auth_token, container, http_conn=http_conn) readers = acls.get('x-container-read', '') writers = acls.get('x-container-write', '') return (readers, writers)
def get_cors(storage_url, auth_token, container, http_conn): """ Returns CORS header of given container. """ headers = client.head_container(storage_url, auth_token, container, http_conn=http_conn) cors = headers.get('x-container-meta-access-control-allow-origin', '') return cors
def test_skip_sync_when_misconfigured(self): source_container, dest_container = self._setup_synced_containers() container_name = 'versioned-%s' % uuid.uuid4() version_hdr = {'X-Versions-Enabled': 'true'} client.put_container(self.url, self.token, container_name, headers=version_hdr) # some sanity checks object_name = 'object-%s' % uuid.uuid4() client.put_object(self.url, self.token, container_name, object_name, 'version1') client.put_object(self.url, self.token, container_name, object_name, 'version2') resp_headers, listing = client.get_container( self.url, self.token, container_name, query_string='versions') self.assertEqual(2, len(listing)) sync_headers = {} sync_to = '//%s/%s/%s/%s' % (self.realm, self.cluster, self.account, dest_container) sync_headers['X-Container-Sync-To'] = sync_to sync_headers['X-Container-Sync-Key'] = 'secret' # use internal client to set container-sync headers # since it doesn't have container_sync middleware in pipeline # allowing us to bypass checks int_client = self.make_internal_client() # TODO: what a terrible hack, maybe we need to extend internal # client to allow caller to become a swift_owner?? int_client.app.app.app.app.swift_owner_headers = [] int_client.set_container_metadata(self.account, container_name, metadata=sync_headers) headers = client.head_container(self.url, self.token, container_name) # This should never happen, but if it does because of eventual # consistency or a messed up pipeline, container-sync should # skip syncing container. self.assertEqual('True', headers.get('x-versions-enabled')) self.assertEqual('secret', headers.get('x-container-sync-key')) self.assertEqual(sync_to, headers.get('x-container-sync-to')) # cycle container-sync Manager(['container-sync']).once() with self.assertRaises(ClientException) as cm: client.get_object( self.url, self.token, dest_container, object_name) self.assertEqual(404, cm.exception.http_status) # sanity check
def get_acls(request, container): """ Read and return the Read and Write ACL of the given container. """ storage_url = request.session.get("storage_url", "") auth_token = request.session.get("auth_token", "") cont = client.head_container(storage_url, auth_token, container) readers = split_acl(cont.get("x-container-read", "")) writers = split_acl(cont.get("x-container-write", "")) return JsonResponse({"read_acl": readers, "write_acl": writers})
def container_status(url, token, container_name): """ Returns status of container. :param url: storage url. :param token: auth token from keystone. :param container_name: name of container to return status. :return: dict of information on specified container. """ status = sc.head_container(url, token, container_name) return status
def cache_set(self, context, plan_name, key, contents): """Stores an object Allows the storage of jsonable objects except for None Storing None equals to a cache delete. """ swift_client = self.get_object_client(context) if contents is None: self.cache_delete(context, plan_name, key) return try: swift_client.head_container(constants.TRIPLEO_CACHE_CONTAINER) except swiftexceptions.ClientException: swift_client.put_container(constants.TRIPLEO_CACHE_CONTAINER) swift_client.put_object(constants.TRIPLEO_CACHE_CONTAINER, self._cache_key(plan_name, key), zlib.compress(json.dumps(contents).encode()))
def check_incomplete_slo(request, storage_url, auth_token, container, prefix=None): '''Check the header 'x-container-meta-slo' for the names of SLO that are incomplete. Return a list of the names of objects and the percentage it is complete.''' incomplete_slo = [] try: headers = client.head_container(storage_url, auth_token, container) except client.ClientException, e: return HttpResponse(e, status=500)
def limited_users_login(request): """ Get and parse the list of containers the user has access to. """ storage_url = request.session.get('storage_url', '') auth_token = request.session.get('auth_token', '') user = request.session.get('user', '') # Get list of containers the user has access to in # "X-Container-Meta-container-list" of the container that matches the # user's username. try: meta = client.head_container(storage_url, auth_token, user) # Save the storage_url and auth_token as the default # These values will be the ones reused to validate the session in # session_valid. request.session["default_storage_url"] = storage_url request.session["default_auth_token"] = auth_token except client.ClientException: # The user may belong to more than one tenant and so the user's # container my be in another tenant. Switch to the next tenant # in the tenant list. for i, tenant in enumerate(request.session["tenants"]): if tenant == request.session["tenant_name"]: if i + 1 <= len(request.session["tenants"]): return redirect( swiftbrowser.views.main.switch_tenant, request.session["tenants"][i + 1], True) else: # We've tried all the tenants, no container exists messages.add_message( request, messages.ERROR, _("Unable to find container {0} in any tenant." .format(user))) break return redirect(swiftbrowser.views.main.login) # List of containers if not "x-container-meta-container-list" in meta: # User does not have access to any container but it's own containers = request.session["tenant_name"] + ":" + user else: containers = meta["x-container-meta-container-list"] # Save the mapping of tenants and containers the user has access to. if not request.session.get('container_mapping', ''): request.session['container_mapping'] = get_tenant_container_mapping( containers) return redirect(limited_users_containerview)
def cache_set(self, context, plan_name, key, contents): """Stores an object Allows the storage of jsonable objects except for None Storing None equals to a cache delete. """ swift_client = self.get_object_client(context) if contents is None: self.cache_delete(context, plan_name, key) return try: swift_client.head_container(constants.TRIPLEO_CACHE_CONTAINER) except swiftexceptions.ClientException: swift_client.put_container(constants.TRIPLEO_CACHE_CONTAINER) swift_client.put_object( constants.TRIPLEO_CACHE_CONTAINER, self._cache_key(plan_name, key), zlib.compress(json.dumps(contents).encode()))
def copyMoveSingle(self, destPath, isMove): src = '/'.join(self.path.split('/')[2:]) dst = '/'.join(destPath.split('/')[2:]) src_cont = self.path.split('/')[1] dst_cont = destPath.split('/')[1] headers = {'X-Copy-From': self.path} try: client.head_container(self.storage_url, self.auth_token, dst_cont, headers=headers, http_conn=self.http_connection) except client.ClientException as ex: client.put_container(self.storage_url, self.auth_token, dst_cont, headers=headers, http_conn=self.http_connection) try: client.put_object(self.storage_url, self.auth_token, dst_cont, dst, headers=headers, http_conn=self.http_connection) if isMove: client.delete_object(self.storage_url, self.auth_token, src_cont, src, http_conn=self.http_connection) except client.ClientException: pass
def get_fine_grained_temp_key(storage_url, auth_token, container_name=None): """ Tries to get meta-temp-url key from account or container. If not set, generate tempurl and save it. """ logging.debug(' in get_fine_grained_temp_key: container_name:%s, \ storage_url:%s ' % (container_name, storage_url) ) try: if container_name: container = client.head_container(storage_url, auth_token, container_name) key = container.get('x-container-meta-temp-url-key') logging.debug(' key in get_fine_grained_temp_key container: %s ' % key) else: account = client.head_account(storage_url, auth_token) key = account.get('x-account-meta-temp-url-key') logging.debug(' key in get_fine_grained_temp_key account: %s ' % key) except client.ClientException: return None # logging.debug(' account or container in get_temp_key: %s ' # % account or container) if not key: chars = string.ascii_lowercase + string.digits key = ''.join(random.choice(chars) for x in range(32)) if container_name: headers = {'x-container-meta-temp-url-key': key} try: client.post_container(storage_url, auth_token, container_name, headers) logging.debug(' post_container') except client.ClientException: return None raise ValueError('cannot get key, have no account rights to \ get account key!') else: headers = {'x-account-meta-temp-url-key': key} try: client.post_account(storage_url, auth_token, headers) logging.debug(' post_account') except client.ClientException: return None return key
def get_original_account(storage_url, auth_token, container): try: headers = client.head_container(storage_url, auth_token, container) msp = headers.get('x-container-meta-storage-path') if msp is None: account = storage_url.split('/')[-1] original_container_name = container else: account = msp.split('/')[2] original_container_name = '_'.join(container.split('_')[2:]) except client.ClientException as e: logger.error("Cannot head container %s . Error: %s " % (container, str(e))) return (None, None) return (account, original_container_name)
def get_tempurl_key(): (storage_url, auth_token) = client.get_auth( settings.SWIFT_AUTH_URL, settings.SWIFT_USER, settings.SWIFT_PASSWORD) try: meta = client.head_container(storage_url, auth_token, settings.SWIFT_CONTAINER) key = meta.get('x-container-meta-temp-url-key') except client.ClientException: client.put_container(storage_url, auth_token, settings.SWIFT_CONTAINER) key = None if not key: key = random_key() headers = {'x-container-meta-temp-url-key': key} client.post_container(storage_url, auth_token, settings.SWIFT_CONTAINER, headers) return storage_url, key
def limited_users_containerview(request): """ Display the containers the user has access to within the current tenant.""" storage_url = request.session.get('storage_url', '') auth_token = request.session.get('auth_token', '') container_list = [] keys = {} container_mapping = request.session.get('container_mapping', '') if not container_mapping: messages.add_message( request, messages.ERROR, _("No container mapping.")) return redirect(swiftbrowser.views.main.login) # Get keys for all the containers for container_name in container_mapping[request.session["tenant_name"]]: # Make sure user has access to the container try: meta = client.head_container( storage_url, auth_token, container_name) except client.ClientException: messages.add_message( request, messages.ERROR, _("Failed to head container {0}.".format(container_name))) return redirect(swiftbrowser.views.main.login) container_list.append({"name": container_name}) keys[container_name] = meta.get('x-container-meta-temp-url-key', '') # Store the keys for later use request.session["keys"] = keys return render_to_response('limited_containerview.html', { 'containers': container_list, 'session': request.session, }, context_instance=RequestContext(request))
def disable_versioning(request, container): """ Enable/Disable versioning in container. """ storage_url = get_endpoint(request, 'adminURL') auth_token = get_token_id(request) http_conn = client.http_connection(storage_url, insecure=settings.SWIFT_INSECURE) try: headers = client.head_container(storage_url, auth_token, container, http_conn=http_conn) except client.ClientException as err: log.exception('Exception: {0}'.format(err)) messages.add_message(request, messages.ERROR, _('Access denied.')) return False version_location = headers.get('x-versions-location', None) if version_location: try: client.post_container(storage_url, auth_token, container, headers={'x-versions-location': ''}, http_conn=http_conn) actionlog.log(request.user.username, "update", container) except client.ClientException as err: log.exception('{}{}'.format(_('Exception:').encode('UTF-8'), err)) messages.add_message(request, messages.ERROR, _('Access denied.')) return False deleted = delete_container(request=request, container=version_location) if not deleted: return False messages.add_message(request, messages.SUCCESS, _('Versioning disabled.')) return True
def test_set_acl(self): headers = {'X-Container-Read': 'adam'} swift_client.post_container(self.url, self.token, self.container, headers) headers = {'X-Storlet-Container-Read': 'john', 'X-Storlet-Name': 'mystorlet-1.0.jar'} swift_client.post_container(self.url, self.token, self.container, headers) headers = swift_client.head_container(self.url, self.token, self.container) read_acl = headers['x-container-read'] expected_acl = ('adam,.r:storlets' '.john_mystorlet-1.0.jar') self.assertEqual(expected_acl, read_acl)
def test_set_acl(self): headers = {'X-Container-Read': 'adam'} swift_client.post_container(self.url, self.token, self.container, headers) headers = {'X-Storlet-Container-Read': 'john', 'X-Storlet-Name': 'mystorlet-1.0.jar'} swift_client.post_container(self.url, self.token, self.container, headers) headers = swift_client.head_container(self.url, self.token, self.container) read_acl = headers['x-container-read'] expected_acl = ('adam,.r:storlets' '.john_mystorlet-1.0.jar') self.assertEqual(read_acl, expected_acl)
def test_enable_syncing_while_versioned(self): source_container, dest_container = self._setup_synced_containers() container_name = 'versioned-%s' % uuid.uuid4() version_hdr = {'X-Versions-Enabled': 'true'} client.put_container(self.url, self.token, container_name, headers=version_hdr) # fails to configure as a container-sync source sync_headers = {'X-Container-Sync-Key': 'secret'} sync_to = '//%s/%s/%s/%s' % (self.realm, self.cluster, self.account, dest_container) sync_headers['X-Container-Sync-To'] = sync_to with self.assertRaises(ClientException) as cm: client.post_container(self.url, self.token, container_name, headers=sync_headers) self.assertEqual(400, cm.exception.http_status) # sanity check # but works if it's just a container-sync destination sync_headers = {'X-Container-Sync-Key': 'secret'} client.post_container(self.url, self.token, container_name, headers=sync_headers) headers = client.head_container(self.url, self.token, container_name) self.assertEqual('True', headers.get('x-versions-enabled')) self.assertEqual('secret', headers.get('x-container-sync-key')) # update source header to sync to versioned container source_headers = {'X-Container-Sync-Key': 'secret'} sync_to = '//%s/%s/%s/%s' % (self.realm, self.cluster, self.account, container_name) source_headers['X-Container-Sync-To'] = sync_to client.post_container(self.url, self.token, source_container, headers=source_headers) self._test_syncing(source_container, container_name)
def test_enable_versioning_while_syncing_container(self): source_container, dest_container = self._setup_synced_containers() version_hdr = {'X-Versions-Enabled': 'true'} # Cannot enable versioning on source container with self.assertRaises(ClientException) as cm: client.post_container(self.url, self.token, source_container, headers=version_hdr) self.assertEqual(400, cm.exception.http_status) # sanity check self.assertEqual(b'Cannot enable object versioning on a container ' b'configured as source of container syncing.', cm.exception.http_response_content) # but destination is ok! client.post_container(self.url, self.token, dest_container, headers=version_hdr) headers = client.head_container(self.url, self.token, dest_container) self.assertEqual('True', headers.get('x-versions-enabled')) self.assertEqual('secret', headers.get('x-container-sync-key')) self._test_syncing(source_container, dest_container)
def object_versioning(request, container, prefix=None): storage_url = get_endpoint(request, 'adminURL') auth_token = get_token_id(request) public_url = get_endpoint(request, 'publicURL') + '/' + container http_conn = client.http_connection(storage_url, insecure=settings.SWIFT_INSECURE) objects = [] page = request.GET.get('page', 1) if request.method == 'GET': headers = client.head_container(storage_url, auth_token, container, http_conn=http_conn) version_location = headers.get('x-versions-location', None) if version_location: try: _, objects = client.get_container(storage_url, auth_token, version_location, prefix=prefix, delimiter='/', http_conn=http_conn) except client.ClientException: pass prefixes = prefix_list(prefix) object_list = pseudofolder_object_list(objects, prefix, public_url) context = utils.update_default_context( request, { 'container': container, 'objects': utils.generic_pagination(object_list, page), 'version_location': version_location, 'prefix': prefix, 'prefixes': prefixes, }) return render_to_response('container_versioning.html', dictionary=context, context_instance=RequestContext(request)) if request.method == 'POST': action = request.POST.get('action', None) if action == 'enable': enable_versioning(request, container) actionlog.log(request.user.username, "enable", 'Versioning. Container: %s' % container) elif action == 'disable': disable_versioning(request, container) actionlog.log(request.user.username, "disable", 'Versioning. Container: %s' % container) else: messages.add_message(request, messages.ERROR, ugettext('Action is required.')) return redirect(object_versioning, container=container)
def objectview(request, container, prefix=None): """ Returns list of all objects in current container. """ storage_url = request.session.get("storage_url", "") auth_token = request.session.get("auth_token", "") # Users with no role use container keys if request.session.get("norole"): container_object = client.head_container(storage_url, auth_token, container) key = container_object.get("x-container-meta-temp-url-key", "") # Regular users use account keys else: account = client.head_account(storage_url, auth_token) key = account.get("x-account-meta-temp-url-key", "") request.session["container"] = container request.session["prefix"] = prefix request.session["key"] = key redirect_url = get_base_url(request) redirect_url += reverse("objectview", kwargs={"container": container}) try: meta, objects = client.get_container(storage_url, auth_token, container, delimiter="/", prefix=prefix) except client.ClientException: messages.add_message(request, messages.ERROR, _("Access denied.")) return redirect(containerview) # Check CORS header - BASE_URL should be in there. Do not perform this # check for users with no role. No role users will not be accessing # containers in any way except for swiftbrowser. Hence their container has # the proper headers. Norole users are unable to set the header anyways. if meta.get("x-container-meta-access-control-allow-origin") != settings.BASE_URL and not request.session.get( "norole", False ): # Add CORS headers so user can upload to this container. headers = { "X-Container-Meta-Access-Control-Expose-Headers": "Access-Control-Allow-Origin", "X-Container-Meta-Access-Control-Allow-Origin": settings.BASE_URL, } try: client.put_container(storage_url, auth_token, container, headers) except client.ClientException: messages.add_message(request, messages.ERROR, _("Access denied, unable to set CORS header.")) return redirect(containerview) prefixes = prefix_list(prefix) pseudofolders, objs = pseudofolder_object_list(objects, prefix) base_url = get_base_url(request) account = storage_url.split("/")[-1] read_acl = meta.get("x-container-read", "").split(",") public = False required_acl = [".r:*", ".rlistings"] swift_url = storage_url + "/" + container + "/" swift_slo_url = storage_url + "/" + container + "_segments/" if prefix: swift_url += prefix swift_slo_url += prefix redirect_url += prefix signature = create_formpost_signature(swift_url, key) slo_signature = create_formpost_signature(swift_slo_url, key) if [x for x in read_acl if x in required_acl]: public = True return render_to_response( "objectview.html", { "swift_url": swift_url, "swift_slo_url": swift_slo_url, "signature": signature, "slo_signature": slo_signature, "redirect_url": redirect_url, "container": container, "objects": objs, "folders": pseudofolders, "session": request.session, "prefix": prefix, "prefixes": prefixes, "base_url": base_url, "account": account, "public": public, "max_file_size": 5368709120, "max_file_count": 1, "expires": int(time.time() + 60 * 60 * 2), }, context_instance=RequestContext(request), )
def test_account_listing(self): versions_header_key = 'X-Versions-Enabled' # Create container1 container_name = 'container1' obj_name = 'object1' client.put_container(self.url, self.token, container_name) # Assert account level sees it self._assert_account_level(container_name, hdr_cont_count='1', hdr_obj_count='0', hdr_bytes='0', cont_count=0, cont_bytes=0) # Enable versioning hdrs = {versions_header_key: 'True'} client.post_container(self.url, self.token, container_name, hdrs) # write multiple versions of same obj client.put_object(self.url, self.token, container_name, obj_name, 'version1') client.put_object(self.url, self.token, container_name, obj_name, 'version2') # Assert account level doesn't see object data yet, but it # does see the update for the hidden container self._assert_account_level(container_name, hdr_cont_count='2', hdr_obj_count='0', hdr_bytes='0', cont_count=0, cont_bytes=0) # Get to final state self.get_to_final_state() # Assert account level now sees updated values # N.B: Note difference in values between header and container listing # header object count is counting both symlink + object versions # listing count is counting only symlink (in primary container) self._assert_account_level(container_name, hdr_cont_count='2', hdr_obj_count='3', hdr_bytes='16', cont_count=1, cont_bytes=16) client.delete_object(self.url, self.token, container_name, obj_name) _headers, current_versions = client.get_container( self.url, self.token, container_name) self.assertEqual(len(current_versions), 0) _headers, all_versions = client.get_container(self.url, self.token, container_name, query_string='versions') self.assertEqual(len(all_versions), 3) # directly delete primary container to leave an orphan hidden # container self.direct_delete_container(container=container_name) # Get to final state self.get_to_final_state() # The container count decreases, as well as object count. But bytes # do not. The discrepancy between header object count, container # object count and bytes should indicate orphan hidden container is # still around consuming storage self._assert_account_level(container_name, hdr_cont_count='1', hdr_obj_count='3', hdr_bytes='16', cont_count=0, cont_bytes=16) # Can't HEAD or list anything, though with self.assertRaises(client.ClientException) as caught: client.head_container(self.url, self.token, container_name) self.assertEqual(caught.exception.http_status, 404) with self.assertRaises(client.ClientException) as caught: client.get_container(self.url, self.token, container_name) self.assertEqual(caught.exception.http_status, 404) with self.assertRaises(client.ClientException) as caught: client.get_container(self.url, self.token, container_name, query_string='versions') self.assertEqual(caught.exception.http_status, 404) with self.assertRaises(client.ClientException) as caught: client.get_object(self.url, self.token, container_name, all_versions[1]['name'], query_string='version-id=%s' % all_versions[1]['version_id']) # A little funny -- maybe this should 404 instead? self.assertEqual(caught.exception.http_status, 400) # Fix isn't too bad -- just make the container again! client.put_container(self.url, self.token, container_name) _headers, current_versions = client.get_container( self.url, self.token, container_name) self.assertEqual(len(current_versions), 0) _headers, all_versions = client.get_container(self.url, self.token, container_name, query_string='versions') self.assertEqual(len(all_versions), 3) # ... but to actually *access* the versions, you have to enable # versioning again with self.assertRaises(client.ClientException) as caught: client.get_object(self.url, self.token, container_name, all_versions[1]['name'], query_string='version-id=%s' % all_versions[1]['version_id']) self.assertEqual(caught.exception.http_status, 400) self.assertIn(b'version-aware operations require', caught.exception.http_response_content) client.post_container(self.url, self.token, container_name, headers={'X-Versions-Enabled': 'true'}) client.get_object(self.url, self.token, container_name, all_versions[1]['name'], query_string='version-id=%s' % all_versions[1]['version_id'])
def get_container_metadata(self, swift_url, swift_container): return swift.head_container(swift_url, self.keystone.get_token('id'), swift_container)
def objectview(request, container, prefix=None): """ Returns list of all objects in current container. """ storage_url = request.session.get('storage_url', '') auth_token = request.session.get('auth_token', '') # Users with no role use container keys if request.session.get('norole'): key = request.session.get("keys")[container] # Regular users use account keys else: account = client.head_account(storage_url, auth_token) key = account.get('x-account-meta-temp-url-key', '') request.session['container'] = container request.session['prefix'] = prefix request.session["key"] = key try: meta = client.head_container( storage_url, auth_token, container, headers={"X-Forwarded-For": request.META.get('REMOTE_ADDR')}) except client.ClientException: messages.add_message(request, messages.ERROR, _("Access denied.")) return redirect(containerview) # Check CORS header - BASE_URL should be in there. Do not perform this # check for users with no role. No role users will not be accessing # containers in any way except for swiftbrowser. Hence their container has # the proper headers. Norole users are unable to set the header anyways. if meta.get( 'x-container-meta-access-control-allow-origin' ) != settings.BASE_URL and not request.session.get('norole', False): # Add CORS headers so user can upload to this container. headers = { 'X-Container-Meta-Access-Control-Expose-Headers': 'Access-Control-Allow-Origin', 'X-Container-Meta-Access-Control-Allow-Origin': settings.BASE_URL, } try: client.put_container( storage_url, auth_token, container, headers) except client.ClientException: messages.add_message(request, messages.ERROR, _( "Access denied, unable to set CORS header.")) return redirect(containerview) prefixes = prefix_list(prefix) base_url = get_base_url(request) account = storage_url.split('/')[-1] read_acl = meta.get('x-container-read', '').split(',') public = False required_acl = ['.r:*', '.rlistings'] # The swifturl is the URL that the browser can send posts to upload files. swift_url = storage_url + '/' + container + '/' swift_slo_url = storage_url + '/' + container + '_segments/' if prefix: swift_url += prefix swift_slo_url += prefix # Posts from the browser to swift need a valid signature that's created # from the tempurl key signature = create_formpost_signature(swift_url, key) slo_signature = create_formpost_signature(swift_slo_url, key) if [x for x in read_acl if x in required_acl]: public = True return render_to_response( "objectview.html", { 'swift_url': swift_url, 'swift_slo_url': swift_slo_url, 'signature': signature, 'slo_signature': slo_signature, 'container': container, 'session': request.session, 'prefix': prefix, 'prefixes': prefixes, 'base_url': base_url, 'account': account, 'public': public, 'max_file_size': 5368709120, 'max_file_count': 1, 'expires': int(time.time() + 60 * 60 * 2), }, context_instance=RequestContext(request) )