Exemple #1
0
    def PUT(self, env, start_response):
        """ Handle non-CDMI Object update and create request. """

        # First check if the resource exists and if it is a directory
        path = '/' + concat_parts('v1', self.account_name, self.container_name,
                                  self.parent_name, self.object_name)

        exists, headers, body = check_resource(env, 'HEAD', path, self.logger,
                                               False, None)

        if exists:
            content_type = headers.get('content-type', '')
            content_type = content_type.lower() if content_type else ''
            if content_type.find('application/directory') >= 0:
                return get_err_response('Conflict')
        else:
            path = '/' + concat_parts('v1', self.account_name,
                                      self.container_name)

            query_string = 'delimiter=/&prefix=' + \
                concat_parts(self.parent_name, self.object_name) + '/'

            parent_exists, dummy, body = check_resource(env, 'GET', path,
                                                        self.logger, True,
                                                        query_string)

            if parent_exists:
                try:
                    children = json.loads(body)
                    if len(children) > 0:
                        #No children under, no resource exist
                        return get_err_response('Conflict')
                except ValueError:
                    return get_err_response('InconsistantState')
            else:
                return get_err_response('NoParentContainer')

        # Check if the parent is OK. it should be either a real directory
        # or a virtual directory
        res = self._check_parent(env, start_response)
        if res:
            return res

        # Create a new WebOb Request object according to the current request
        req = Request(env)

        if not req.body or len(req.body) == 0:
            req.headers['content-length'] = '0'
        res = req.get_response(self.app)
        return res
    def _capability(self, env, start_response):

        res, is_container, headers, children = \
            self._check_resource_attribute(env, start_response)

        if res:
            return res

        res = Response()
        res.status = 200
        res.headers['Content-Type'] = Consts.CDMI_APP_CAPABILITY
        res.headers[Consts.CDMI_VERSION] = Consts.CDMI_VERSION_VALUE

        body = {}
        body['objectType'] = Consts.CDMI_APP_CAPABILITY

        if self.object_name:
            body['parentURI'] = concat_parts(self.cdmi_capability_id,
                                             self.account_name,
                                             self.container_name,
                                             self.parent_name) + '/'
        else:
            body['parentURI'] = concat_parts(self.cdmi_capability_id,
                                             self.account_name) + '/'

        body['capabilities'] = {}
        if is_container:
            if self.object_name:
                body['objectName'] = self.object_name + '/'
            else:
                body['objectName'] = self.container_name + '/'

            body['capabilities']['cdmi_list_children'] = True
            body['capabilities']['cdmi_read_metadata'] = True
            body['capabilities']['cdmi_modify_metadata'] = True
            body['capabilities']['cdmi_create_dataobject'] = True
            body['capabilities']['cdmi_delete_container'] = True
            body['capabilities']['cdmi_create_container'] = True
        else:
            body['objectName'] = self.object_name
            body['capabilities']['cdmi_read_value'] = True
            body['capabilities']['cdmi_read_metadata'] = True
            body['capabilities']['cdmi_modify_value'] = True
            body['capabilities']['cdmi_modify_metadata'] = True
            body['capabilities']['cdmi_delete_dataobject'] = True

        res.body = json.dumps(body, indent=2)
        return res
Exemple #3
0
    def PUT(self, env, start_response):
        """ Handle Container update and create request """

        # First check if the resource exists and if it is a directory
        path = '/' + concat_parts('v1', self.account_name, self.container_name,
                                  self.parent_name, self.object_name)

        exists, headers, body = check_resource(env, 'HEAD', path,
                                               self.logger, False)

        if exists:
            content_type = headers.get('content-type', '')
            content_type = content_type.lower() if content_type else ''
            if (content_type.find('application/directory') < 0 and
                self.object_name):
                return get_err_response('Conflict')
        else:
            res = self._check_parent(env, start_response)
            if res:
                return res

        req = Request(env)
        req.headers['content-type'] = 'application/directory'
        req.headers['content-length'] = '0'
        req.body = ''
        res = req.get_response(self.app)
        return res
    def DELETE(self, env, start_response):
        """
        Handle DELETE both container and data object removal.
        """

        path = '/v1/' + self.account_name + '/' + self.container_name
        query_string = 'delimiter=/'
        if self.object_name:
            query_string += '&prefix=' + concat_parts(self.parent_name,
                                                      self.object_name) + '/'
        exists, dummy, body = check_resource(env, 'GET', path, self.logger,
                                             True, query_string)
        # Not even the top container exist, so there is no such resource.
        if not exists:
            return get_err_response('NoSuchKey')
        # Top container exists, check if there is anything under.
        else:
            try:
                children = json.loads(body)
                #there are some children under
                if len(children) > 0:
                    return get_err_response('ContainerNotEmpty')
            except ValueError:
                return get_err_response('InconsistantState')

        # Create a new WebOb Request object according to the current request
        req = Request(env)
        # Now send the request over.
        return req.get_response(self.app)
    def _read_object(self, env, start_response, headers):

        req = Request(env)
        os_res = req.get_response(self.app)

        cdmi_version = env.get('HTTP_X_CDMI_SPECIFICATION_VERSION', False)
        # If this is not a CDMI content request, simply return the response
        if not cdmi_version:
            return os_res

        # For CDMI content request, more work need to be done.
        res = Response()
        # Set up CDMI required headers
        res.headers[Consts.CDMI_VERSION] = Consts.CDMI_VERSION_VALUE
        res.headers['Content-Type'] = Consts.CDMI_APP_OBJECT

        object_body = os_res.body
        # Build the response message body according to CDMI specification
        body = {}

        # Setup required attributes for response body
        body['objectType'] = Consts.CDMI_APP_OBJECT
        body['objectName'] = self.object_name
        body['parentURI'] = concat_parts(self.account_name,
                                         self.parent_name) + '/'
        body['capabilitiesURI'] = concat_parts(self.cdmi_capability_id,
                                               self.account_name,
                                               self.container_name,
                                               self.parent_name,
                                               self.object_name) + '/'
        body['completionStatus'] = 'Complete'
        body['metadata'] = {}

        # Handling CDMI metadata
        body['metadata'] = self._process_metadata(headers)
        body['mimetype'] = headers.get('content-type', '')
        body['valuetransferencoding'] = \
            headers.get(Consts.VALUE_ENCODING, 'utf-8')
        body['valuerange'] = '0-' + str(len(object_body))
        body['value'] = object_body
        res.body = json.dumps(body, indent=2)
        res.status_int = 200

        return res
    def _check_parent(self, env, start_response):
        """
        This method checks if the parent really represents a directory.
        Returns error if parent does not exist or the parent actually points
        to a non directory. Returns None means that the parent points to a
        valid container (top container or virtual container)
        """
        if self.parent_name:
            # Try to hit the resource url and see if it exists
            path = '/' + concat_parts('v1', self.account_name,
                                      self.container_name, self.parent_name)
            exists, headers, dummy = check_resource(env, 'HEAD',
                                                    path, self.logger)
            if exists:
                content_type = str(headers.get('content-type', ''))
                if content_type.find('application/directory') < 0:
                    return get_err_response('InvalidContainerName')
                else:
                    return None
            else:
                # Check if there is anything below that parent, if it is,
                # then this is actually a virtual container.
                path = '/' + concat_parts('v1', self.account_name,
                                          self.container_name)
                query_string = 'delimiter=/&prefix=' + self.parent_name + '/'
                parent_exists, dummy, body = check_resource(env, 'GET', path,
                                                            self.logger, True,
                                                            query_string)
                if parent_exists:
                    try:
                        children = json.loads(body)
                        if len(children) <= 0:
                            # No children under, no resource exist
                            return get_err_response('NoParentContainer')
                        else:
                            return None
                    except ValueError:
                        return get_err_response('InconsistantState')
                # The root container does not event exist, this is an error
                else:
                    return get_err_response('NoParentContainer')

        return None
 def __init__(self, env, conf, app, logger, account_name, container_name,
              parent_name, object_name, **kwargs):
     Controller.__init__(self, conf, app, logger)
     self.account_name = account_name
     self.container_name = container_name
     self.object_name = object_name
     self.parent_name = parent_name
     if self.object_name:
         self.metadata_prefix = Consts.META_OBJECT_ID
     else:
         self.metadata_prefix = Consts.META_CONTAINER_ID
     env['PATH_INFO'] = '/v1/' + concat_parts(self.account_name,
                                              self.container_name,
                                              self.parent_name,
                                              self.object_name)
Exemple #8
0
    def get_controller(self, env, path, cdmi_version, method):
        if path.startswith("/" + self.cdmi_root):
            content_type = (env.get("CONTENT_TYPE") or "").lower()
            accept = (env.get("HTTP_ACCEPT") or "").lower()

            content_is_container = content_type.find("application/cdmi-container") >= 0 or False

            content_is_object = content_type.find("application/cdmi-object") >= 0 or False

            accept_is_container = accept.find("application/cdmi-container") >= 0 or False

            accept_is_object = accept.find("application/cdmi-object") >= 0 or False

            content_length = int(env.get("CONTENT_LENGTH") or "0")

            subs = path.lstrip("/ ").rstrip("/ ").split("/")

            # We first get rid of the cdmi_root which is no important
            # for rest of the work
            subs = subs[self.cdmi_root_length :]
            subs[len(subs) :] = [None, None, None, None]
            if subs[0] == self.cdmi_capability_id:
                is_capability_request = True
                subs = subs[1:]
            else:
                is_capability_request = False

            account_name = subs[0]
            container_name = subs[1]
            parent_name = concat_parts(*subs[2:])
            if parent_name == "":
                parent_name = None
                object_name = None
            else:
                newsubs = parent_name.split("/")
                object_name = newsubs[-1]
                parent_name = "/".join(newsubs[0:-1])

            if method in ["GET"]:
                if account_name is None:
                    controller = LoginController
                elif container_name is None:
                    controller = AccountController
                    if is_capability_request:
                        env["HTTP_ACCEPT"] = "application/cdmi-capability"
                else:
                    controller = CDMICommonController
                    if is_capability_request:
                        env["HTTP_ACCEPT"] = "application/cdmi-capability"
                    # To setup a flag so that we know what the request wants
                    if content_is_container or accept_is_container or path.endswith("/"):
                        env["X-WANTS-CONTAINER"] = "True"
                d = dict(container_name=container_name, parent_name=parent_name, object_name=object_name)
                return account_name, controller, d
            elif method in ["PUT"]:
                if account_name:
                    if cdmi_version:
                        # Ensure that accept headers indicate what the client
                        # want to do, header overwrite trailing slash
                        # Only when no headers, the trailing slash plays
                        # an important role.
                        if accept_is_container or (path.endswith("/") and not accept_is_object):
                            controller = ContainerController
                        elif accept_is_object or not path.endswith("/"):
                            controller = ObjectController
                        else:
                            controller = ErrorController
                    else:
                        if path.endswith("/"):
                            controller = NonCDMIContainerController
                        else:
                            controller = NonCDMIObjectController
                else:
                    controller = ErrorController
                d = dict(container_name=container_name, parent_name=parent_name, object_name=object_name)
                return account_name, controller, d
            elif method in ["DELETE"]:
                if account_name is None:
                    controller = ErrorController
                else:
                    controller = CDMICommonController
                d = dict(container_name=container_name, parent_name=parent_name, object_name=object_name)
                return account_name, controller, d
            else:
                controller = ErrorController
                d = dict(container_name=container_name, parent_name=parent_name, object_name=object_name)
                return account_name, controller, d
        else:
            d = dict(container_name=None, object_name=None)
            return None, None, d
Exemple #9
0
    def PUT(self, env, start_response):
        """
        Handle Container update and create request
        """

        # First check if the resource exists and if it is a directory
        path = '/' + concat_parts('v1', self.account_name, self.container_name,
                                  self.parent_name, self.object_name)
        exists, headers, dummy = check_resource(env, 'HEAD', path,
                                                self.logger, False)
        if exists:
            content_type = headers.get('content-type', '')
            content_type = content_type.lower() if content_type else ''
            if (content_type.find('application/directory') < 0 and
                self.object_name):
                return get_err_response('Conflict')
        # Not a top container, so it has to be virtual container
        else:
            res = self._check_parent(env, start_response)
            if res:
                return res

        # Create a new WebOb Request object according to the current request
        req = Request(env)

        # We are creating a container, set the content-type to be
        # application/directory
        req.headers['content-type'] = 'application/directory'

        metadata = {}
        if req.body:
            try:
                body = json.loads(req.body)
            except ValueError:
                return get_err_response('InvalidContent')

            metadata = body.get('metadata')
            if metadata:
                for key in metadata:
                    if metadata[key] == '':
                        req.headers[self.metadata_prefix + key] = ''
                    else:
                        req.headers[self.metadata_prefix + key] = \
                            key + ":" + str(metadata[key])
            else:
                metadata = {}

        # Now set the body to be empty and content-length to 0
        req.body = ''
        req.headers['Content-Length'] = 0

        res = req.get_response(self.app)

        # Deal with the response now.
        # Build the response message body according to CDMI specification
        # if the response status is 201, then we know we have successfully
        # created the container. According to CDMI spec, only send response
        # body when creating new container
        if res.status_int == 201:
            body = {}
            body['objectType'] = Consts.CDMI_APP_CONTAINER
            body['objectName'] = self.object_name if self.object_name else \
                self.container_name
            if self.object_name:
                body['parentURI'] = concat_parts(self.account_name,
                                                 self.container_name,
                                                 self.parent_name) + '/'
            else:
                body['parentURI'] = self.account_name + '/'
            body['completionStatus'] = 'Complete'
            body['metadata'] = metadata
            res.body = json.dumps(body, indent=2)
        # Otherwise, no body should be returned.
        else:
            res.body = ''

        return res
Exemple #10
0
    def PUT(self, env, start_response):
        """
        Handle Container update and create request
        """
        # First check if the resource exists and if it is a directory
        path = '/' + concat_parts('v1', self.account_name, self.container_name,
                                  self.parent_name, self.object_name)
        exists, headers, body = check_resource(env, 'HEAD', path, self.logger,
                                               False, None)
        if exists:
            content_type = headers.get('content-type', '')
            content_type = content_type.lower() if content_type else ''
            if content_type.find('application/directory') >= 0:
                return get_err_response('Conflict')
        else:
            path = '/' + concat_parts('v1', self.account_name,
                                      self.container_name)
            query_string = 'delimiter=/&prefix=' + \
                concat_parts(self.parent_name, self.object_name) + '/'
            parent_exists, dummy, body = check_resource(env, 'GET', path,
                                                        self.logger, True,
                                                        query_string)
            if parent_exists:
                try:
                    children = json.loads(body)
                    if len(children) > 0:
                        # No children under, no resource exist
                        return get_err_response('Conflict')
                except ValueError:
                    return get_err_response('InconsistantState')
            else:
                return get_err_response('NoParentContainer')

        # Check if the parent is OK. it should be either a real directory or
        # a virtual directory
        res = self._check_parent(env, start_response)
        if res:
            return res

        # Create a new WebOb Request object according to the current request
        req = Request(env)

        metadata = {}
        if req.body:
            try:
                body = json.loads(req.body)
            except ValueError:
                return get_err_response('InvalidContent')

            if body.get('metadata'):
                metadata = body['metadata']
                for key in metadata:
                    if metadata[key] == '':
                        req.headers[Consts.META_OBJECT_ID + key] = ''
                    else:
                        req.headers[Consts.META_OBJECT_ID + key] = \
                            key + ":" + str(metadata[key])
            else:
                metadata = {}

            try:
                req.body = str(body.get('value', ''))
                req.headers['content-type'] = body.get('mimetype',
                                                       'text/plain')
                req.headers[Consts.VALUE_ENCODING] = \
                    body.get('valuetransferencoding', 'utf-8')
            except KeyError:
                return get_err_response('InvalidContent')
        else:
            req.headers['content-length'] = '0'

        res = req.get_response(self.app)

        # Deal with the response now.
        # Build the response message body according to CDMI specification
        # If the response status is 201, then we know we have successfully
        # created the object. According to CDMI spec, only send response body
        # when creating new object.
        if res.status_int == 201:
            body = {}
            body['objectType'] = Consts.CDMI_APP_OBJECT
            body['objectName'] = self.object_name
            body['parentURI'] = concat_parts(self.account_name,
                                             self.container_name,
                                             self.parent_name) + '/'
            body['completionStatus'] = 'Complete'
            body['metadata'] = metadata
            res.body = json.dumps(body, indent=2)
        # Otherwise, no response body should be returned.
        else:
            res.body = ''

        return res
Exemple #11
0
    def _read_container(self, env, start_response, headers, children):

        # Build the response message body according to CDMI specification
        res = Response()
        res.headers['content-type'] = 'application/json; charset=UTF-8'

        body = {}

        # Setup required attributes for response body
        body['objectType'] = Consts.CDMI_APP_CONTAINER
        if self.object_name:
            body['objectName'] = self.object_name + '/'
            body['parentURI'] = concat_parts(self.account_name,
                                             self.container_name,
                                             self.parent_name) + '/'
        else:
            body['objectName'] = self.container_name + '/'
            body['parentURI'] = self.account_name + '/'

        body['capabilitiesURI'] = concat_parts(self.cdmi_capability_id,
                                               self.account_name,
                                               self.container_name,
                                               self.parent_name,
                                               self.object_name) + '/'
        body['completionStatus'] = 'Complete'
        body['metadata'] = {}

        #Get CDMI metadata from the header and add to the body
        for header, value in headers.iteritems():
            key = header.lower()
            if key.startswith(self.metadata_prefix):
                key, value = get_pair_from_header(value)
                if key != '' and value != '':
                    body['metadata'][key] = value

        body['children'] = []
        if children:
            string_to_cut = concat_parts(self.parent_name, self.object_name)
            size = len(string_to_cut)
            if size > 0:
                size += 1
            tracking_device = {}
            for child in children:
                if child.get('name', False):
                    child_name = child.get('name')
                else:
                    child_name = child.get('subdir', False)
                if child_name:
                    child_name = child_name[size:]
                    if not child_name.endswith('/'):
                        content_type = child.get('content_type', '')
                        if content_type.find('directory') >= 0:
                            child_name += '/'
                    if tracking_device.get(child_name) is None:
                        tracking_device[child_name] = child_name
                        body['children'].append(child_name)

        res.body = json.dumps(body, indent=2)
        res.status_int = 200

        return res
Exemple #12
0
    def _check_resource_attribute(self, env, start_response):
        """
        This method checks if a given url points to either a container, or
        an object or does not exist. It will also check if a resource is a
        virtual container in CDMI term. If a resource exists, the headers
        will also be return in following sequence.
        res - The response which containers errors, None means there is no
        error
        is_container - if it is a container, it is True, otherwise, it is
        False
        headers - if the resource exists, this holds the headers
        children - if it is a container, return container's child list
        """
        path = env['PATH_INFO']
        res, is_container, headers, children = None, False, {}, None
        exists, headers, dummy = check_resource(env, 'HEAD', path, self.logger)
        # If exists, we need to check if the resource is a container
        if exists:
            content_type = (headers.get('content-type') or '').lower()
            if (content_type.find('application/directory') < 0 and
                self.object_name):
                is_container = False
            else:
                is_container = True
        # None self.object_name means that we are dealing with a real OS
        # container, return resource not found error
        elif not self.object_name:
            res = get_err_response('NoSuchKey')

        if res is None and (not exists or is_container):
            # Now we will try to get the children of the container and also
            # do more checks to see if there is any virtual resources.
            path = '/' + concat_parts('v1', self.account_name,
                                      self.container_name)
            query_string = 'delimiter=/'
            if self.object_name:
                query_string += ('&prefix=' +
                                 concat_parts(self.parent_name,
                                              self.object_name) +
                                 '/')

            container_exists, dummy, body = check_resource(env, 'GET', path,
                                                           self.logger, True,
                                                           query_string)
            if container_exists:
                try:
                    children = json.loads(body)
                    no_of_children = len(children)
                    # The entity could be a virtual container since it
                    # does not exist
                    if not exists:
                        # There is no children under also not exists,
                        # it is not virtual container.
                        if no_of_children <= 0:
                            res = get_err_response('NoSuchKey')
                        # There are children under and not exist, it is
                        # a virtual container
                        elif no_of_children > 0 and not exists:
                            is_container = True
                except ValueError:
                    res = get_err_response('InconsistantState')
            else:
                res = get_err_response('NoSuchKey')

        self.logger.info('is_container=' + str(is_container))
        self.logger.info(res)
        return res, is_container, headers, children