¡@

Home 

OpenStack Study: container.py

OpenStack Index

**** CubicPower OpenStack Study ****

# Copyright (c) 2010-2012 OpenStack Foundation

#

# 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.

from swift import gettext_ as _

from urllib import unquote

import time

from swift.common.utils import public, csv_append, normalize_timestamp

from swift.common.constraints import check_metadata, MAX_CONTAINER_NAME_LENGTH

from swift.common.http import HTTP_ACCEPTED

from swift.proxy.controllers.base import Controller, delay_denial, \

cors_validation, clear_info_cache

from swift.common.swob import HTTPBadRequest, HTTPForbidden, \

HTTPNotFound

**** CubicPower OpenStack Study ****

class ContainerController(Controller):

"""WSGI controller for container requests"""

server_type = 'Container'

# Ensure these are all lowercase

pass_through_headers = ['x-container-read', 'x-container-write',

'x-container-sync-key', 'x-container-sync-to',

'x-versions-location']

**** CubicPower OpenStack Study ****

    def __init__(self, app, account_name, container_name, **kwargs):

        Controller.__init__(self, app)

        self.account_name = unquote(account_name)

        self.container_name = unquote(container_name)

**** CubicPower OpenStack Study ****

    def _x_remove_headers(self):

        st = self.server_type.lower()

        return ['x-remove-%s-read' % st,

                'x-remove-%s-write' % st,

                'x-remove-versions-location']

**** CubicPower OpenStack Study ****

    def clean_acls(self, req):

        if 'swift.clean_acl' in req.environ:

            for header in ('x-container-read', 'x-container-write'):

                if header in req.headers:

                    try:

                        req.headers[header] = \

                            req.environ['swift.clean_acl'](header,

                                                           req.headers[header])

                    except ValueError as err:

                        return HTTPBadRequest(request=req, body=str(err))

        return None

**** CubicPower OpenStack Study ****

    def GETorHEAD(self, req):

        """Handler for HTTP GET/HEAD requests."""

        if not self.account_info(self.account_name, req)[1]:

            return HTTPNotFound(request=req)

        part = self.app.container_ring.get_part(

            self.account_name, self.container_name)

        resp = self.GETorHEAD_base(

            req, _('Container'), self.app.container_ring, part,

            req.swift_entity_path)

        if 'swift.authorize' in req.environ:

            req.acl = resp.headers.get('x-container-read')

            aresp = req.environ['swift.authorize'](req)

            if aresp:

                return aresp

        if not req.environ.get('swift_owner', False):

            for key in self.app.swift_owner_headers:

                if key in resp.headers:

                    del resp.headers[key]

        return resp

    @public

    @delay_denial

    @cors_validation

**** CubicPower OpenStack Study ****

    def GET(self, req):

        """Handler for HTTP GET requests."""

        return self.GETorHEAD(req)

    @public

    @delay_denial

    @cors_validation

**** CubicPower OpenStack Study ****

    def HEAD(self, req):

        """Handler for HTTP HEAD requests."""

        return self.GETorHEAD(req)

    @public

    @cors_validation

**** CubicPower OpenStack Study ****

    def PUT(self, req):

        """HTTP PUT request handler."""

        error_response = \

            self.clean_acls(req) or check_metadata(req, 'container')

        if error_response:

            return error_response

        if not req.environ.get('swift_owner'):

            for key in self.app.swift_owner_headers:

                req.headers.pop(key, None)

        if len(self.container_name) > MAX_CONTAINER_NAME_LENGTH:

            resp = HTTPBadRequest(request=req)

            resp.body = 'Container name length of %d longer than %d' % \

                        (len(self.container_name), MAX_CONTAINER_NAME_LENGTH)

            return resp

        account_partition, accounts, container_count = \

            self.account_info(self.account_name, req)

        if not accounts and self.app.account_autocreate:

            self.autocreate_account(req.environ, self.account_name)

            account_partition, accounts, container_count = \

                self.account_info(self.account_name, req)

        if not accounts:

            return HTTPNotFound(request=req)

        if self.app.max_containers_per_account > 0 and \

                container_count >= self.app.max_containers_per_account and \

                self.account_name not in self.app.max_containers_whitelist:

            resp = HTTPForbidden(request=req)

            resp.body = 'Reached container limit of %s' % \

                        self.app.max_containers_per_account

            return resp

        container_partition, containers = self.app.container_ring.get_nodes(

            self.account_name, self.container_name)

        headers = self._backend_requests(req, len(containers),

                                         account_partition, accounts)

        clear_info_cache(self.app, req.environ,

                         self.account_name, self.container_name)

        resp = self.make_requests(

            req, self.app.container_ring,

            container_partition, 'PUT', req.swift_entity_path, headers)

        return resp

    @public

    @cors_validation

**** CubicPower OpenStack Study ****

    def POST(self, req):

        """HTTP POST request handler."""

        error_response = \

            self.clean_acls(req) or check_metadata(req, 'container')

        if error_response:

            return error_response

        if not req.environ.get('swift_owner'):

            for key in self.app.swift_owner_headers:

                req.headers.pop(key, None)

        account_partition, accounts, container_count = \

            self.account_info(self.account_name, req)

        if not accounts:

            return HTTPNotFound(request=req)

        container_partition, containers = self.app.container_ring.get_nodes(

            self.account_name, self.container_name)

        headers = self.generate_request_headers(req, transfer=True)

        clear_info_cache(self.app, req.environ,

                         self.account_name, self.container_name)

        resp = self.make_requests(

            req, self.app.container_ring, container_partition, 'POST',

            req.swift_entity_path, [headers] * len(containers))

        return resp

    @public

    @cors_validation

**** CubicPower OpenStack Study ****

    def DELETE(self, req):

        """HTTP DELETE request handler."""

        account_partition, accounts, container_count = \

            self.account_info(self.account_name, req)

        if not accounts:

            return HTTPNotFound(request=req)

        container_partition, containers = self.app.container_ring.get_nodes(

            self.account_name, self.container_name)

        headers = self._backend_requests(req, len(containers),

                                         account_partition, accounts)

        clear_info_cache(self.app, req.environ,

                         self.account_name, self.container_name)

        resp = self.make_requests(

            req, self.app.container_ring, container_partition, 'DELETE',

            req.swift_entity_path, headers)

        # Indicates no server had the container

        if resp.status_int == HTTP_ACCEPTED:

            return HTTPNotFound(request=req)

        return resp

**** CubicPower OpenStack Study ****

    def _backend_requests(self, req, n_outgoing,

                          account_partition, accounts):

        additional = {'X-Timestamp': normalize_timestamp(time.time())}

        headers = [self.generate_request_headers(req, transfer=True,

                                                 additional=additional)

                   for _junk in range(n_outgoing)]

        for i, account in enumerate(accounts):

            i = i % len(headers)

            headers[i]['X-Account-Partition'] = account_partition

            headers[i]['X-Account-Host'] = csv_append(

                headers[i].get('X-Account-Host'),

                '%(ip)s:%(port)s' % account)

            headers[i]['X-Account-Device'] = csv_append(

                headers[i].get('X-Account-Device'),

                account['device'])

        return headers