Exemplo n.º 1
0
 def POST(self, req):
     """Handle HTTP POST request."""
     drive, part, account, container = split_and_validate_path(req, 4)
     if 'x-timestamp' not in req.headers or \
             not check_float(req.headers['x-timestamp']):
         return HTTPBadRequest(body='Missing or bad timestamp',
                               request=req,
                               content_type='text/plain')
     if 'x-container-sync-to' in req.headers:
         err = validate_sync_to(req.headers['x-container-sync-to'],
                                self.allowed_sync_hosts)
         if err:
             return HTTPBadRequest(err)
     if self.mount_check and not check_mount(self.root, drive):
         return HTTPInsufficientStorage(drive=drive, request=req)
     broker = self._get_container_broker(drive, part, account, container)
     if broker.is_deleted():
         return HTTPNotFound(request=req)
     timestamp = normalize_timestamp(req.headers['x-timestamp'])
     metadata = {}
     metadata.update((key, (value, timestamp))
                     for key, value in req.headers.iteritems()
                     if key.lower() in self.save_headers
                     or key.lower().startswith('x-container-meta-'))
     if metadata:
         if 'X-Container-Sync-To' in metadata:
             if 'X-Container-Sync-To' not in broker.metadata or \
                     metadata['X-Container-Sync-To'][0] != \
                     broker.metadata['X-Container-Sync-To'][0]:
                 broker.set_x_container_sync_points(-1, -1)
         broker.update_metadata(metadata)
     return HTTPNoContent(request=req)
Exemplo n.º 2
0
 def HEAD(self, req):
     """Handle HTTP HEAD request."""
     drive, part, account, container, obj = split_and_validate_path(
         req, 4, 5, True)
     out_content_type = listing_formats.get_listing_content_type(req)
     try:
         check_drive(self.root, drive, self.mount_check)
     except ValueError:
         return HTTPInsufficientStorage(drive=drive, request=req)
     broker = self._get_container_broker(drive,
                                         part,
                                         account,
                                         container,
                                         pending_timeout=0.1,
                                         stale_reads_ok=True)
     info, is_deleted = broker.get_info_is_deleted()
     headers = gen_resp_headers(info, is_deleted=is_deleted)
     if is_deleted:
         return HTTPNotFound(request=req, headers=headers)
     headers.update(
         (key, value)
         for key, (value, timestamp) in broker.metadata.items()
         if value != '' and (key.lower() in self.save_headers
                             or is_sys_or_user_meta('container', key)))
     headers['Content-Type'] = out_content_type
     resp = HTTPNoContent(request=req, headers=headers, charset='utf-8')
     resp.last_modified = math.ceil(float(headers['X-PUT-Timestamp']))
     return resp
Exemplo n.º 3
0
 def HEAD(self, req):
     """Handle HTTP HEAD request."""
     drive, part, account, container, obj = split_and_validate_path(
         req, 4, 5, True)
     out_content_type = get_listing_content_type(req)
     if self.mount_check and not check_mount(self.root, drive):
         return HTTPInsufficientStorage(drive=drive, request=req)
     broker = self._get_container_broker(drive,
                                         part,
                                         account,
                                         container,
                                         pending_timeout=0.1,
                                         stale_reads_ok=True)
     if broker.is_deleted():
         return HTTPNotFound(request=req)
     info = broker.get_info()
     headers = {
         'X-Container-Object-Count': info['object_count'],
         'X-Container-Bytes-Used': info['bytes_used'],
         'X-Timestamp': info['created_at'],
         'X-PUT-Timestamp': info['put_timestamp'],
     }
     headers.update(
         (key, value)
         for key, (value, timestamp) in broker.metadata.iteritems()
         if value != '' and (key.lower() in self.save_headers or
                             key.lower().startswith('x-container-meta-')))
     headers['Content-Type'] = out_content_type
     return HTTPNoContent(request=req, headers=headers, charset='utf-8')
Exemplo n.º 4
0
 def POST(self, req):
     """Handle HTTP POST request."""
     drive, part, account, container = split_and_validate_path(req, 4)
     req_timestamp = valid_timestamp(req)
     if 'x-container-sync-to' in req.headers:
         err, sync_to, realm, realm_key = validate_sync_to(
             req.headers['x-container-sync-to'], self.allowed_sync_hosts,
             self.realms_conf)
         if err:
             return HTTPBadRequest(err)
     if not check_drive(self.root, drive, self.mount_check):
         return HTTPInsufficientStorage(drive=drive, request=req)
     broker = self._get_container_broker(drive, part, account, container)
     if broker.is_deleted():
         return HTTPNotFound(request=req)
     broker.update_put_timestamp(req_timestamp.internal)
     metadata = {}
     metadata.update(
         (key, (value, req_timestamp.internal))
         for key, value in req.headers.items()
         if key.lower() in self.save_headers or
         is_sys_or_user_meta('container', key))
     if metadata:
         if 'X-Container-Sync-To' in metadata:
             if 'X-Container-Sync-To' not in broker.metadata or \
                     metadata['X-Container-Sync-To'][0] != \
                     broker.metadata['X-Container-Sync-To'][0]:
                 broker.set_x_container_sync_points(-1, -1)
         broker.update_metadata(metadata, validate_metadata=True)
         self._update_sync_store(broker, 'POST')
     return HTTPNoContent(request=req)
Exemplo n.º 5
0
    def handle_change_secret_key(self, req, access_key):
        """Change current secret key for given access key.

        Required headers:
         - `x-s3auth-secret-key-old`: must match current secret key
         - `x-s3auth-secret-key-new`: the new secret key
        """
        secret_old = req.headers.get('x-s3auth-secret-key-old')
        secret_new = req.headers.get('x-s3auth-secret-key-new')

        if not (secret_old and secret_new):
            return HTTPBadRequest(
                body='x-s3auth-secret-key-old and x-s3auth-secret-key-new '
                'headers required',
                request=req)

        secret_key, account = self._get_details(req, access_key)
        if secret_key:
            if secret_key == secret_old:
                self._set_details(req, access_key, secret_new, account)
                return HTTPNoContent(request=req)
            else:
                return _denied_response(req)
        else:
            return _denied_response(req)
Exemplo n.º 6
0
    def DELETE(self, req):
        """Handle HTTP DELETE request."""
        drive, part, account, container, obj = split_and_validate_path(
            req, 4, 5, True)
        req_timestamp = valid_timestamp(req)
        try:
            check_drive(self.root, drive, self.mount_check)
        except ValueError:
            return HTTPInsufficientStorage(drive=drive, request=req)
        # policy index is only relevant for delete_obj (and transitively for
        # auto create accounts)
        obj_policy_index = self.get_and_validate_policy_index(req) or 0
        broker = self._get_container_broker(drive, part, account, container)
        if account.startswith(self.auto_create_account_prefix) and obj and \
                not os.path.exists(broker.db_file):
            try:
                broker.initialize(req_timestamp.internal, obj_policy_index)
            except DatabaseAlreadyExists:
                pass
        if not os.path.exists(broker.db_file):
            return HTTPNotFound()
        if obj:  # delete object
            # redirect if a shard range exists for the object name
            redirect = self._redirect_to_shard(req, broker, obj)
            if redirect:
                return redirect

            broker.delete_object(obj, req.headers.get('x-timestamp'),
                                 obj_policy_index)
            return HTTPNoContent(request=req)
        else:
            # delete container
            if not broker.empty():
                return HTTPConflict(request=req)
            existed = Timestamp(broker.get_info()['put_timestamp']) and \
                not broker.is_deleted()
            broker.delete_db(req_timestamp.internal)
            if not broker.is_deleted():
                return HTTPConflict(request=req)
            self._update_sync_store(broker, 'DELETE')
            resp = self.account_update(req, account, container, broker)
            if resp:
                return resp
            if existed:
                return HTTPNoContent(request=req)
            return HTTPNotFound()
Exemplo n.º 7
0
class AccountController(object):
    """WSGI controller for the account server."""
    def __init__(self, conf):
        self.logger = get_logger(conf, log_route='account-server')
        self.root = conf.get('devices', '/srv/node')
        self.mount_check = config_true_value(conf.get('mount_check', 'true'))
        replication_server = conf.get('replication_server', None)
        if replication_server is None:
            allowed_methods = [
                'DELETE', 'PUT', 'HEAD', 'GET', 'REPLICATE', 'POST'
            ]
        else:
            replication_server = config_true_value(replication_server)
            if replication_server:
                allowed_methods = ['REPLICATE']
            else:
                allowed_methods = ['DELETE', 'PUT', 'HEAD', 'GET', 'POST']
        self.replication_server = replication_server
        self.allowed_methods = allowed_methods
        self.replicator_rpc = ReplicatorRpc(self.root,
                                            DATADIR,
                                            AccountBroker,
                                            self.mount_check,
                                            logger=self.logger)
        self.auto_create_account_prefix = \
            conf.get('auto_create_account_prefix') or '.'
        swift.common.db.DB_PREALLOCATION = \
            config_true_value(conf.get('db_preallocation', 'f'))

    def _get_account_broker(self, drive, part, account):
        hsh = hash_path(account)
        db_dir = storage_directory(DATADIR, part, hsh)
        db_path = os.path.join(self.root, drive, db_dir, hsh + '.db')
        return AccountBroker(db_path, account=account, logger=self.logger)

    @public
    @timing_stats()
    def DELETE(self, req):
        """Handle HTTP DELETE request."""
        try:
            drive, part, account = req.split_path(3)
            validate_device_partition(drive, part)
        except ValueError, err:
            return HTTPBadRequest(body=str(err),
                                  content_type='text/plain',
                                  request=req)
        if self.mount_check and not check_mount(self.root, drive):
            return HTTPInsufficientStorage(drive=drive, request=req)
        if 'x-timestamp' not in req.headers or \
                not check_float(req.headers['x-timestamp']):
            return HTTPBadRequest(body='Missing timestamp',
                                  request=req,
                                  content_type='text/plain')
        broker = self._get_account_broker(drive, part, account)
        if broker.is_deleted():
            return HTTPNotFound(request=req)
        broker.delete_db(req.headers['x-timestamp'])
        return HTTPNoContent(request=req)
Exemplo n.º 8
0
    def origin_db_delete(self, env, req):
        """
        Handles DELETEs in the Origin database.
        This is not really a delete- it will remove the object from the
        container listing and set cdn_enabled=false and a deleted flag in the
        .hash_* obj that says that the obj is deleted. This way the container
        won't show up in the listings, HEAD to the object will return 404s but
        behind the scenes lookups to the object will be able to determine
        the account and container from a container_hash.
        """
        try:
            vsn, account, container = split_path(req.path, 3, 3)
        except ValueError:
            return HTTPBadRequest(
                'Invalid request. '
                'URI format: /<api version>/<account>/<container>')
        if self.extra_header_for_deletes and not req.headers.get(
                self.extra_header_for_deletes, 'f').lower() in TRUE_VALUES:
            # only do delete if header is set (assuming you want the header)
            return HTTPMethodNotAllowed(request=req)
        hsh = self.hash_path(account, container)
        cdn_obj_path = self.get_hsh_obj_path(hsh)

        # Remove memcache entry
        memcache_client = utils.cache_from_env(env)
        if memcache_client:
            memcache_key = self.cdn_data_memcache_key(cdn_obj_path)
            memcache_client.delete(memcache_key)

        ref_hash_data = HashData(account,
                                 container,
                                 self.default_ttl,
                                 False,
                                 False,
                                 deleted=True)
        self._set_hash_data(env,
                            cdn_obj_path,
                            ref_hash_data,
                            update_listings=False)

        cdn_list_path = quote('/v1/%s/%s/%s' %
                              (self.origin_account, account, container))
        list_resp = make_pre_authed_request(env,
                                            'DELETE',
                                            cdn_list_path,
                                            agent='SwiftOrigin',
                                            swift_source='SOS').get_response(
                                                self.app)

        if list_resp.status_int // 100 != 2 and list_resp.status_int != 404:
            raise OriginDbFailure('Could not DELETE listing path in origin '
                                  'db: %s %s' %
                                  (cdn_list_path, list_resp.status_int))

        # Return 404 if container didn't exist
        if list_resp.status_int == 404:
            return HTTPNotFound(request=req)
        return HTTPNoContent(request=req)
Exemplo n.º 9
0
 def PUT(self, req):
     """Handle HTTP PUT request."""
     drive, part, account, container = split_and_validate_path(req, 3, 4)
     if self.mount_check and not check_mount(self.root, drive):
         return HTTPInsufficientStorage(drive=drive, request=req)
     if container:   # put account container
         pending_timeout = None
         if 'x-trans-id' in req.headers:
             pending_timeout = 3
         broker = self._get_account_broker(drive, part, account,
                                           pending_timeout=pending_timeout)
         if account.startswith(self.auto_create_account_prefix) and \
                 not os.path.exists(broker.db_file):
             try:
                 broker.initialize(normalize_timestamp(
                     req.headers.get('x-timestamp') or time.time()))
             except DatabaseAlreadyExists:
                 pass
         if req.headers.get('x-account-override-deleted', 'no').lower() != \
                 'yes' and broker.is_deleted():
             return HTTPNotFound(request=req)
         broker.put_container(container, req.headers['x-put-timestamp'],
                              req.headers['x-delete-timestamp'],
                              req.headers['x-object-count'],
                              req.headers['x-bytes-used'])
         if req.headers['x-delete-timestamp'] > \
                 req.headers['x-put-timestamp']:
             return HTTPNoContent(request=req)
         else:
             return HTTPCreated(request=req)
     else:   # put account
         broker = self._get_account_broker(drive, part, account)
         timestamp = normalize_timestamp(req.headers['x-timestamp'])
         if not os.path.exists(broker.db_file):
             try:
                 broker.initialize(timestamp)
                 created = True
             except DatabaseAlreadyExists:
                 created = False
         elif broker.is_status_deleted():
             return self._deleted_response(broker, req, HTTPForbidden,
                                           body='Recently deleted')
         else:
             created = broker.is_deleted()
             broker.update_put_timestamp(timestamp)
             if broker.is_deleted():
                 return HTTPConflict(request=req)
         metadata = {}
         metadata.update((key, (value, timestamp))
                         for key, value in req.headers.iteritems()
                         if key.lower().startswith('x-account-meta-'))
         if metadata:
             broker.update_metadata(metadata)
         if created:
             return HTTPCreated(request=req)
         else:
             return HTTPAccepted(request=req)
Exemplo n.º 10
0
def account_listing_response(account, req, response_content_type,
                             info=None, listing=None, s3_buckets_only=False):
    now = time.time()
    if info is None:
        info = {'containers': 0,
                'objects': 0,
                'bytes': 0,
                'metadata': {},
                'ctime': Timestamp(now).internal}
    if listing is None:
        listing = []
    elif listing and len(listing[0]) < 5:
        # oio-sds < 4.2 does not return mtime
        listing = [x + [now] for x in listing]

    resp_headers = get_response_headers(info)

    if response_content_type == 'application/json':
        data = []
        for (name, object_count, bytes_used, is_subdir, mtime) in listing:
            if is_subdir:
                if not s3_buckets_only:
                    data.append({'subdir': name})
            else:
                data.append({'name': name, 'count': object_count,
                             'bytes': bytes_used,
                             'last_modified': Timestamp(mtime).isoformat})
        account_list = json.dumps(data)
    elif response_content_type.endswith('/xml'):
        output_list = ['<?xml version="1.0" encoding="UTF-8"?>',
                       '<account name=%s>' % saxutils.quoteattr(account)]
        for (name, object_count, bytes_used, is_subdir, mtime) in listing:
            if is_subdir:
                if not s3_buckets_only:
                    output_list.append(
                        '<subdir name=%s />' % saxutils.quoteattr(name))
            else:
                item = '<container><name>%s</name><count>%s</count>' \
                       '<bytes>%s</bytes><last_modified>%s</last_modified>' \
                       '</container>' % \
                       (saxutils.escape(name), object_count, bytes_used,
                        Timestamp(mtime).isoformat)
                output_list.append(item)
        output_list.append('</account>')
        account_list = '\n'.join(output_list)
    else:
        if not listing:
            resp = HTTPNoContent(request=req, headers=resp_headers)
            resp.content_type = response_content_type
            resp.charset = 'utf-8'
            return resp
        account_list = '\n'.join(r[0] for r in listing) + '\n'
    ret = HTTPOk(body=account_list, request=req, headers=resp_headers)
    ret.content_type = response_content_type
    ret.charset = 'utf-8'
    return ret
Exemplo n.º 11
0
def account_listing_response(account,
                             req,
                             response_content_type,
                             broker=None,
                             limit='',
                             marker='',
                             end_marker='',
                             prefix='',
                             delimiter='',
                             reverse=False):
    if broker is None:
        broker = FakeAccountBroker()

    resp_headers = get_response_headers(broker)

    account_list = broker.list_containers_iter(limit, marker, end_marker,
                                               prefix, delimiter, reverse)
    if response_content_type == 'application/json':
        data = []
        for (name, object_count, bytes_used, is_subdir) in account_list:
            if is_subdir:
                data.append({'subdir': name})
            else:
                data.append({
                    'name': name,
                    'count': object_count,
                    'bytes': bytes_used
                })
        account_list = json.dumps(data)
    elif response_content_type.endswith('/xml'):
        output_list = [
            '<?xml version="1.0" encoding="UTF-8"?>',
            '<account name=%s>' % saxutils.quoteattr(account)
        ]
        for (name, object_count, bytes_used, is_subdir) in account_list:
            if is_subdir:
                output_list.append('<subdir name=%s />' %
                                   saxutils.quoteattr(name))
            else:
                item = '<container><name>%s</name><count>%s</count>' \
                       '<bytes>%s</bytes></container>' % \
                       (saxutils.escape(name), object_count, bytes_used)
                output_list.append(item)
        output_list.append('</account>')
        account_list = '\n'.join(output_list)
    else:
        if not account_list:
            resp = HTTPNoContent(request=req, headers=resp_headers)
            resp.content_type = response_content_type
            resp.charset = 'utf-8'
            return resp
        account_list = '\n'.join(r[0] for r in account_list) + '\n'
    ret = HTTPOk(body=account_list, request=req, headers=resp_headers)
    ret.content_type = response_content_type
    ret.charset = 'utf-8'
    return ret
Exemplo n.º 12
0
 def get_account_post_resp(self, req, headers):
     metadata = {}
     metadata.update((key, value)
                     for key, value in req.headers.items()
                     if is_sys_or_user_meta('account', key))
     try:
         self.app.storage.account_update(self.account_name, metadata)
         return HTTPNoContent(request=req)
     except (exceptions.NotFound, exceptions.NoSuchAccount):
         if self.app.account_autocreate:
             self.autocreate_account(req, self.account_name)
             if metadata:
                 self.app.storage.account_update(
                         self.account_name, metadata, headers=headers)
             resp = HTTPNoContent(request=req)
         else:
             resp = HTTPNotFound(request=req)
     self.add_acls_from_sys_metadata(resp)
     return resp
Exemplo n.º 13
0
 def complete_rsync(self, drive, db_file, args):
     old_filename = os.path.join(self.root, drive, 'tmp', args[0])
     if os.path.exists(db_file):
         return HTTPNotFound()
     if not os.path.exists(old_filename):
         return HTTPNotFound()
     broker = self.broker_class(old_filename)
     broker.newid(args[0])
     renamer(old_filename, db_file)
     return HTTPNoContent()
Exemplo n.º 14
0
 def get_container_head_resp(self, req):
     headers = dict()
     out_content_type = get_listing_content_type(req)
     headers['Content-Type'] = out_content_type
     oio_headers = {REQID_HEADER: self.trans_id}
     meta = self.app.storage.container_get_properties(self.account_name,
                                                      self.container_name,
                                                      headers=oio_headers)
     headers.update(self.get_metadata_resp_headers(meta))
     return HTTPNoContent(request=req, headers=headers, charset='utf-8')
Exemplo n.º 15
0
 def get_container_delete_resp(self, req):
     oio_headers = {REQID_HEADER: self.trans_id}
     try:
         self.app.storage.container_delete(self.account_name,
                                           self.container_name,
                                           headers=oio_headers)
     except exceptions.ContainerNotEmpty:
         return HTTPConflict(request=req)
     resp = HTTPNoContent(request=req)
     return resp
Exemplo n.º 16
0
 def DELETE(self, req):
     """Handle HTTP DELETE request."""
     drive, part, account, container, obj = split_and_validate_path(
         req, 4, 5, True)
     if 'x-timestamp' not in req.headers or \
             not check_float(req.headers['x-timestamp']):
         return HTTPBadRequest(body='Missing timestamp', request=req,
                               content_type='text/plain')
     if self.mount_check and not check_mount(self.root, drive):
         return HTTPInsufficientStorage(drive=drive, request=req)
     broker = self._get_container_broker(drive, part, account, container)
     if account.startswith(self.auto_create_account_prefix) and obj and \
             not os.path.exists(broker.db_file):
         requested_policy_index = (self.get_and_validate_policy_index(req)
                                   or POLICIES.default.idx)
         try:
             broker.initialize(
                 normalize_timestamp(
                     req.headers.get('x-timestamp') or time.time()),
                 requested_policy_index)
         except DatabaseAlreadyExists:
             pass
     if not os.path.exists(broker.db_file):
         return HTTPNotFound()
     if obj:     # delete object
         broker.delete_object(obj, req.headers.get('x-timestamp'))
         return HTTPNoContent(request=req)
     else:
         # delete container
         if not broker.empty():
             return HTTPConflict(request=req)
         existed = float(broker.get_info()['put_timestamp']) and \
             not broker.is_deleted()
         broker.delete_db(req.headers['X-Timestamp'])
         if not broker.is_deleted():
             return HTTPConflict(request=req)
         resp = self.account_update(req, account, container, broker)
         if resp:
             return resp
         if existed:
             return HTTPNoContent(request=req)
         return HTTPNotFound()
Exemplo n.º 17
0
 def get_container_delete_resp(self, req, headers):
     oio_headers = {'X-oio-req-id': self.trans_id}
     try:
         self.app.storage.container_delete(
             self.account_name, self.container_name, headers=oio_headers)
     except exceptions.ContainerNotEmpty:
         return HTTPConflict(request=req)
     except exceptions.NoSuchContainer:
         return HTTPNotFound(request=req)
     resp = HTTPNoContent(request=req)
     return resp
Exemplo n.º 18
0
 def get_container_delete_resp(self, req):
     oio_headers = {REQID_HEADER: self.trans_id}
     oio_cache = req.environ.get('oio.cache')
     perfdata = req.environ.get('oio.perfdata')
     try:
         self.app.storage.container_delete(
             self.account_name, self.container_name, headers=oio_headers,
             cache=oio_cache, perfdata=perfdata)
     except exceptions.ContainerNotEmpty:
         return HTTPConflict(request=req)
     resp = HTTPNoContent(request=req)
     return resp
Exemplo n.º 19
0
def account_listing_response(account, req, response_content_type, broker=None,
                             limit='', marker='', end_marker='', prefix='',
                             delimiter=''):
    if broker is None:
        broker = FakeAccountBroker()

    info = broker.get_info()
    resp_headers = {
        'X-Account-Container-Count': info['container_count'],
        'X-Account-Object-Count': info['object_count'],
        'X-Account-Bytes-Used': info['bytes_used'],
        'X-Timestamp': info['created_at'],
        'X-PUT-Timestamp': info['put_timestamp']}
    resp_headers.update((key, value)
                        for key, (value, timestamp) in
                        broker.metadata.iteritems() if value != '')

    account_list = broker.list_containers_iter(limit, marker, end_marker,
                                               prefix, delimiter)
    if response_content_type == 'application/json':
        data = []
        for (name, object_count, bytes_used, is_subdir) in account_list:
            if is_subdir:
                data.append({'subdir': name})
            else:
                data.append({'name': name, 'count': object_count,
                             'bytes': bytes_used})
        account_list = json.dumps(data)
    elif response_content_type.endswith('/xml'):
        output_list = ['<?xml version="1.0" encoding="UTF-8"?>',
                       '<account name=%s>' % saxutils.quoteattr(account)]
        for (name, object_count, bytes_used, is_subdir) in account_list:
            if is_subdir:
                output_list.append(
                    '<subdir name=%s />' % saxutils.quoteattr(name))
            else:
                item = '<container><name>%s</name><count>%s</count>' \
                       '<bytes>%s</bytes></container>' % \
                       (saxutils.escape(name), object_count, bytes_used)
                output_list.append(item)
        output_list.append('</account>')
        account_list = '\n'.join(output_list)
    else:
        if not account_list:
            resp = HTTPNoContent(request=req, headers=resp_headers)
            resp.content_type = response_content_type
            resp.charset = 'utf-8'
            return resp
        account_list = '\n'.join(r[0] for r in account_list) + '\n'
    ret = HTTPOk(body=account_list, request=req, headers=resp_headers)
    ret.content_type = response_content_type
    ret.charset = 'utf-8'
    return ret
Exemplo n.º 20
0
 def get_container_create_resp(self, req, headers):
     properties, system = self.properties_from_headers(headers)
     # TODO container update metadata
     oio_headers = {'X-oio-req-id': self.trans_id}
     created = self.app.storage.container_create(
         self.account_name, self.container_name,
         properties=properties, system=system,
         headers=oio_headers)
     if created:
         return HTTPCreated(request=req)
     else:
         return HTTPNoContent(request=req)
Exemplo n.º 21
0
    def origin_db_delete(self, env, req):
        """ Handles DELETEs in the Origin database """
        if not self.delete_enabled:
            return HTTPMethodNotAllowed(request=req)
        try:
            vsn, account, container = split_path(req.path, 3, 3)
        except ValueError:
            return HTTPBadRequest(
                'Invalid request. '
                'URI format: /<api version>/<account>/<container>')
        hsh = self.hash_path(account, container)
        cdn_obj_path = self.get_hsh_obj_path(hsh)

        # Remove memcache entry
        memcache_client = utils.cache_from_env(env)
        if memcache_client:
            memcache_key = self.cdn_data_memcache_key(cdn_obj_path)
            memcache_client.delete(memcache_key)

        resp = make_pre_authed_request(env,
                                       'DELETE',
                                       cdn_obj_path,
                                       agent='SwiftOrigin',
                                       swift_source='SOS').get_response(
                                           self.app)

        # A 404 means it's already deleted, which is okay
        if resp.status_int // 100 != 2 and resp.status_int != 404:
            raise OriginDbFailure('Could not DELETE .hash obj in origin '
                                  'db: %s %s' %
                                  (cdn_obj_path, resp.status_int))

        cdn_list_path = quote('/v1/%s/%s/%s' %
                              (self.origin_account, account, container))
        list_resp = make_pre_authed_request(env,
                                            'DELETE',
                                            cdn_list_path,
                                            agent='SwiftOrigin',
                                            swift_source='SOS').get_response(
                                                self.app)

        if list_resp.status_int // 100 != 2 and list_resp.status_int != 404:
            raise OriginDbFailure('Could not DELETE listing path in origin '
                                  'db: %s %s' %
                                  (cdn_list_path, list_resp.status_int))

        # Return 404 if container didn't exist
        if resp.status_int == 404 and list_resp.status_int == 404:
            return HTTPNotFound(request=req)
        return HTTPNoContent(request=req)
Exemplo n.º 22
0
 def HEAD(self, req):
     """Handle HTTP HEAD request."""
     drive, part, account = split_and_validate_path(req, 3)
     out_content_type = get_listing_content_type(req)
     if self.mount_check and not check_mount(self.root, drive):
         return HTTPInsufficientStorage(drive=drive, request=req)
     broker = self._get_account_broker(drive, part, account,
                                       pending_timeout=0.1,
                                       stale_reads_ok=True)
     if broker.is_deleted():
         return self._deleted_response(broker, req, HTTPNotFound)
     headers = get_response_headers(broker)
     headers['Content-Type'] = out_content_type
     return HTTPNoContent(request=req, headers=headers, charset='utf-8')
Exemplo n.º 23
0
 def __call__(self, env, start_response):
     req = Request(env)
     if env['REQUEST_METHOD'] == 'GET' or env['REQUEST_METHOD'] == 'HEAD':
         if self.status == 200:
             if 'HTTP_RANGE' in env:
                 resp = Response(request=req,
                                 body=self.object_body,
                                 conditional_response=True)
                 return resp(env, start_response)
             start_response(
                 Response(request=req).status,
                 self.response_headers.items())
             if env['REQUEST_METHOD'] == 'GET':
                 return self.object_body
         elif self.status == 401:
             start_response(HTTPUnauthorized(request=req).status, [])
         elif self.status == 403:
             start_response(HTTPForbidden(request=req).status, [])
         elif self.status == 404:
             start_response(HTTPNotFound(request=req).status, [])
         else:
             start_response(HTTPBadRequest(request=req).status, [])
     elif env['REQUEST_METHOD'] == 'PUT':
         if self.status == 201:
             start_response(
                 HTTPCreated(request=req).status,
                 [('etag', self.response_headers['etag'])])
         elif self.status == 401:
             start_response(HTTPUnauthorized(request=req).status, [])
         elif self.status == 403:
             start_response(HTTPForbidden(request=req).status, [])
         elif self.status == 404:
             start_response(HTTPNotFound(request=req).status, [])
         elif self.status == 413:
             start_response(
                 HTTPRequestEntityTooLarge(request=req).status, [])
         else:
             start_response(HTTPBadRequest(request=req).status, [])
     elif env['REQUEST_METHOD'] == 'DELETE':
         if self.status == 204:
             start_response(HTTPNoContent(request=req).status, [])
         elif self.status == 401:
             start_response(HTTPUnauthorized(request=req).status, [])
         elif self.status == 403:
             start_response(HTTPForbidden(request=req).status, [])
         elif self.status == 404:
             start_response(HTTPNotFound(request=req).status, [])
         else:
             start_response(HTTPBadRequest(request=req).status, [])
     return []
Exemplo n.º 24
0
    def get_container_head_resp(self, req):
        headers = dict()
        out_content_type = get_listing_content_type(req)
        headers['Content-Type'] = out_content_type
        oio_headers = {'X-oio-req-id': self.trans_id}
        try:
            meta = self.app.storage.container_get_properties(
                self.account_name, self.container_name, headers=oio_headers)
            headers.update(self.get_metadata_resp_headers(meta))
            resp = HTTPNoContent(request=req, headers=headers, charset='utf-8')
        except exceptions.NoSuchContainer:
            resp = HTTPNotFound(request=req, headers=headers)

        return resp
Exemplo n.º 25
0
 def __call__(self, env, start_response):
     if env['REQUEST_METHOD'] == 'GET':
         if self.status == 200:
             start_response(Response().status,
                            [('Content-Type', 'text/xml')])
             json_pattern = [
                 '"name":%s', '"last_modified":%s', '"hash":%s',
                 '"bytes":%s'
             ]
             json_pattern = '{' + ','.join(json_pattern) + '}'
             json_out = []
             for b in self.objects:
                 name = simplejson.dumps(b[0])
                 time = simplejson.dumps(b[1])
                 json_out.append(json_pattern % (name, time, b[2], b[3]))
             account_list = '[' + ','.join(json_out) + ']'
             return account_list
         elif self.status == 401:
             start_response(HTTPUnauthorized().status, [])
         elif self.status == 403:
             start_response(HTTPForbidden().status, [])
         elif self.status == 404:
             start_response(HTTPNotFound().status, [])
         else:
             start_response(HTTPBadRequest().status, [])
     elif env['REQUEST_METHOD'] == 'PUT':
         if self.status == 201:
             start_response(HTTPCreated().status, [])
         elif self.status == 401:
             start_response(HTTPUnauthorized().status, [])
         elif self.status == 403:
             start_response(HTTPForbidden().status, [])
         elif self.status == 202:
             start_response(HTTPAccepted().status, [])
         else:
             start_response(HTTPBadRequest().status, [])
     elif env['REQUEST_METHOD'] == 'DELETE':
         if self.status == 204:
             start_response(HTTPNoContent().status, [])
         elif self.status == 401:
             start_response(HTTPUnauthorized().status, [])
         elif self.status == 403:
             start_response(HTTPForbidden().status, [])
         elif self.status == 404:
             start_response(HTTPNotFound().status, [])
         elif self.status == 409:
             start_response(HTTPConflict().status, [])
         else:
             start_response(HTTPBadRequest().status, [])
     return []
Exemplo n.º 26
0
    def create_listing(self, req, out_content_type, resp_headers, result,
                       container, **kwargs):
        container_list = result['objects']
        for p in result.get('prefixes', []):
            record = {'name': p, 'subdir': True}
            container_list.append(record)
        container_list.sort(key=lambda x: x['name'])
        ret = Response(request=req,
                       headers=resp_headers,
                       content_type=out_content_type,
                       charset='utf-8')
        versions = kwargs.get('versions', False)
        slo = kwargs.get('slo', False)
        if out_content_type == 'application/json':
            ret.body = json.dumps([
                self.update_data_record(r, versions, slo)
                for r in container_list
            ]).encode('utf-8')
            req.environ['swift.format_listing'] = False
        elif out_content_type.endswith('/xml'):
            doc = Element('container', name=container.decode('utf-8'))
            for obj in container_list:
                record = self.update_data_record(obj, versions, slo)
                if 'subdir' in record:
                    name = record['subdir'].decode('utf-8')
                    sub = SubElement(doc, 'subdir', name=name)
                    SubElement(sub, 'name').text = name
                else:
                    obj_element = SubElement(doc, 'object')
                    for field in [
                            "name", "hash", "bytes", "content_type",
                            "last_modified"
                    ]:
                        SubElement(obj_element, field).text = str(
                            record.pop(field)).decode('utf-8')
                    for field in sorted(record):
                        SubElement(obj_element, field).text = str(
                            record[field]).decode('utf-8')
            ret.body = tostring(doc, encoding='UTF-8').replace(
                "<?xml version='1.0' encoding='UTF-8'?>",
                '<?xml version="1.0" encoding="UTF-8"?>', 1)
            req.environ['swift.format_listing'] = False
        else:
            if not container_list:
                return HTTPNoContent(request=req, headers=resp_headers)
            ret.body = ('\n'.join(rec['name'] for rec in container_list) +
                        '\n').encode('utf-8')

        return ret
Exemplo n.º 27
0
 def create_listing(self, req, out_content_type, info, metadata,
                    container_list, container):
     list_meta = get_param(req, 'list_meta', 'f').lower() in TRUE_VALUES
     resp_headers = {
         'X-Container-Object-Count': info['object_count'],
         'X-Container-Bytes-Used': info['bytes_used'],
         'X-Timestamp': info['created_at'],
         'X-PUT-Timestamp': info['put_timestamp'],
     }
     for key, (value, timestamp) in metadata.iteritems():
         if value and (key.lower() in self.save_headers or
                       is_sys_or_user_meta('container', key)):
             resp_headers[key] = value
     ret = Response(request=req, headers=resp_headers,
                    content_type=out_content_type, charset='utf-8')
     if out_content_type == 'application/json':
         ret.body = json.dumps([self.update_data_record(record, list_meta)
                                for record in container_list])
     elif out_content_type.endswith('/xml'):
         doc = Element('container', name=container.decode('utf-8'))
         for obj in container_list:
             record = self.update_data_record(obj, list_meta)
             if 'subdir' in record:
                 name = record['subdir'].decode('utf-8')
                 sub = SubElement(doc, 'subdir', name=name)
                 SubElement(sub, 'name').text = name
             else:
                 obj_element = SubElement(doc, 'object')
                 for field in ["name", "hash", "bytes", "content_type",
                               "last_modified"]:
                     SubElement(obj_element, field).text = str(
                         record.pop(field)).decode('utf-8')
                 for field in sorted(record):
                     if list_meta and field == 'metadata':
                         meta = SubElement(obj_element, field)
                         for k, v in record[field].iteritems():
                             SubElement(meta, k).text = str(
                                 v.decode('utf-8'))
                     else:
                         SubElement(obj_element, field).text = str(
                             record[field]).decode('utf-8')
         ret.body = tostring(doc, encoding='UTF-8').replace(
             "<?xml version='1.0' encoding='UTF-8'?>",
             '<?xml version="1.0" encoding="UTF-8"?>', 1)
     else:
         if not container_list:
             return HTTPNoContent(request=req, headers=resp_headers)
         ret.body = '\n'.join(rec[0] for rec in container_list) + '\n'
     return ret
Exemplo n.º 28
0
    def get_container_post_resp(self, req, headers):
        properties, system = self.properties_from_headers(headers)
        if not properties:
            return self.PUT(req)

        oio_headers = {'X-oio-req-id': self.trans_id}
        try:
            self.app.storage.container_set_properties(
                self.account_name, self.container_name,
                properties=properties, system=system,
                headers=oio_headers)
            resp = HTTPNoContent(request=req)
        except exceptions.NoSuchContainer:
            resp = self.PUT(req)
        return resp
Exemplo n.º 29
0
 def POST(self, req):
     """Handle HTTP POST request."""
     drive, part, account = split_and_validate_path(req, 3)
     req_timestamp = valid_timestamp(req)
     try:
         check_drive(self.root, drive, self.mount_check)
     except ValueError:
         return HTTPInsufficientStorage(drive=drive, request=req)
     if not self.check_free_space(drive):
         return HTTPInsufficientStorage(drive=drive, request=req)
     broker = self._get_account_broker(drive, part, account)
     if broker.is_deleted():
         return self._deleted_response(broker, req, HTTPNotFound)
     self._update_metadata(req, broker, req_timestamp)
     return HTTPNoContent(request=req)
Exemplo n.º 30
0
class AccountController(object):
    """WSGI controller for the account server."""

    def __init__(self, conf):
        self.logger = get_logger(conf, log_route='account-server')
        self.root = conf.get('devices', '/srv/node')
        self.mount_check = conf.get('mount_check', 'true').lower() in \
            TRUE_VALUES
        self.replicator_rpc = ReplicatorRpc(self.root, DATADIR, AccountBroker,
                                            self.mount_check,
                                            logger=self.logger)
        self.auto_create_account_prefix = \
            conf.get('auto_create_account_prefix') or '.'
        swift.common.db.DB_PREALLOCATION = \
            conf.get('db_preallocation', 'f').lower() in TRUE_VALUES

    def _get_account_broker(self, drive, part, account):
        hsh = hash_path(account)
        db_dir = storage_directory(DATADIR, part, hsh)
        db_path = os.path.join(self.root, drive, db_dir, hsh + '.db')
        return AccountBroker(db_path, account=account, logger=self.logger)

    @public
    def DELETE(self, req):
        """Handle HTTP DELETE request."""
        start_time = time.time()
        try:
            drive, part, account = split_path(unquote(req.path), 3)
            validate_device_partition(drive, part)
        except ValueError, err:
            self.logger.increment('DELETE.errors')
            return HTTPBadRequest(body=str(err), content_type='text/plain',
                                  request=req)
        if self.mount_check and not check_mount(self.root, drive):
            self.logger.increment('DELETE.errors')
            return HTTPInsufficientStorage(drive=drive, request=req)
        if 'x-timestamp' not in req.headers or \
                not check_float(req.headers['x-timestamp']):
            self.logger.increment('DELETE.errors')
            return HTTPBadRequest(body='Missing timestamp', request=req,
                                  content_type='text/plain')
        broker = self._get_account_broker(drive, part, account)
        if broker.is_deleted():
            self.logger.timing_since('DELETE.timing', start_time)
            return HTTPNotFound(request=req)
        broker.delete_db(req.headers['x-timestamp'])
        self.logger.timing_since('DELETE.timing', start_time)
        return HTTPNoContent(request=req)