示例#1
0
    def parse_header_values(self, body):
        """Helper generator method to split values in HTTP Header.

        :param string body: parsed text
        :return: result values
        :rtype: string
        """
        m = None
        while body:
            m = HTTPHeadersRenderer.reHeaderChunk.match(body)
            #print m
            #if m:
            #    print m.groupdict()
            #    print m.end()
            # error on empty match
            if m is None or m.group('chunk') is None or m.end() == 0:
                raise occi.ParseError('Bad quoting in HTTP Headers', body)
                m = None
                break
            chunk = m.group('chunk')
            body = body[m.end():]
            if body and not m.group('sep'):
                raise occi.ParseError('Separator expected in HTTP Headers (%s)' % chunk, body)
                m = None
                break
            yield chunk.strip(' \t')
            #print 'remains: #%s#' % body
        if m and m.group('sep'):
            yield ''
示例#2
0
    def parse_categories(self, body, headers):
        """Parse OCCI Category Collection

        :param string body[]: text to parse
        :param string headers[]: headers to parse (unused in plain/text)
        :return: Array of OCCI Categories
        :rtype: occi.Category[]
        """
        categories = []
        category_ids = set()

        for line in body:
            if not line.strip():
                continue

            matched = TextRenderer.reCategory.match(line)
            if not matched:
                raise occi.ParseError('"category" expected', line)

            category = self.parse_category_body(line[matched.end():])

            # check uniqueness
            key = category['term'] + category['scheme']
            if key in category_ids:
                raise occi.ParseError(
                    'Category not unique (term "%s", scheme "%s")' %
                    (category['term'], category['scheme']), line)
            category_ids.add(key)

            categories.append(category)

        return categories
示例#3
0
    def parse_attribute_defs(self, body):
        """ Parse OCCI Attribute Definitions.

        Example::

           occi.core.id{immutable required} occi.core.title occi.core.target occi.core.source{required}

        :param string body: text to parse
        :return: array of OCCI Attribute Definition
        :rtype: occi.AttributeDefinition[]
        """
        result = []

        m = True
        while m:
            m = TextRenderer.reAttributes.match(body)
            if not m:
                break
            matches = m.groups()
            name = matches[0]
            attrs = matches[1]
            body = body[m.end():]

            if attrs:
                attrs = attrs[1:-1]
                attrs = TextRenderer.reSP.split(attrs)

            attribute = occi.AttributeDefinition({'name': name})
            if attrs:
                for a in attrs:
                    if a == 'required':
                        attribute['required'] = True
                    elif a == 'immutable':
                        attribute['immutable'] = True
                    else:
                        raise occi.ParseError(
                            'Unknown field in OCCI attribute definitions', a)
            result.append(attribute)

        if body:
            raise occi.ParseError('Error parsing OCCI attribute definitions',
                                  body)

        return result
示例#4
0
    def parse_attribute_value(self, body):
        """Parse OCCI Attribute value and detect its type

        string, number, and boolean types are detected, enum is returned as string.

        :param string body: text to parse
        :return: attribute type and value
        :rtype: [string, any]
        """
        if not body:
            raise occi.ParseError('OCCI Attribute value expected')

        matched = TextRenderer.reQuoted.match(body)
        if matched is not None:
            t = 'string'
            value = matched.group(1)
            value = TextRenderer.reStringUnescape.sub(r'\1', value)
            if len(value) + 2 < len(body):
                raise occi.ParseError(
                    'Unexpected quotes in OCCI Attribute value', body)
            return [t, value]

        matched = TextRenderer.reNumber.match(body)
        if matched is not None:
            t = 'number'
            if TextRenderer.reIntNumber.match(body) is not None:
                value = int(matched.group(1))
            else:
                value = float(matched.group(1))
            return [t, value]

        matched = TextRenderer.reBool.match(body)
        if matched is not None:
            t = 'boolean'
            if matched.group(1) == 'false':
                value = False
            else:
                value = True
            return [t, value]

        raise occi.ParseError('Unexpected format of OCCI Attribute value',
                              body)
示例#5
0
    def parse_attribute_body(self, body):
        """Parse OCCI Attribute body

        :param string body: text to parse
        :return: attribute type and value
        :rtype: occi.Attribute
        """

        keyvalue = TextRenderer.reKeyValue.split(body, 1)
        if len(keyvalue) != 2:
            raise occi.ParseError('Attribute invalid syntax', body)

        key = keyvalue[0]
        value = keyvalue[1]
        keymatch = TextRenderer.reKeyCheck.match(key)
        if keymatch is None:
            raise occi.ParseError('Invalid characters in attribute name', key)
        t, v = self.parse_attribute_value(value)

        return occi.Attribute({'name': key, 'type': t, 'value': v})
示例#6
0
    def parse_resource(self, body, header):
        """Parse OCCI Resource instance

        This method can't be used in URI list rendering.

        :param string body[]: text to parse
        :param string headers[]: headers to parse
        :return: categories, links, and attributes
        :rtype: [occi.Category categories[], occi.Link links[], occi.Attribute attributes[]]
        """
        raise occi.ParseError(
            'This method can\'t be used with URI list rendering.')
示例#7
0
    def parse_categories(self, body, headers):
        """Parse OCCI Category Collection

        This method can't be used in URI list rendering.

        :param string body[]: text to parse
        :param string headers[]: headers to parse
        :return: Array of OCCI Categories
        :rtype: occi.Category[]
        """
        raise occi.ParseError(
            'This method can\'t be used with URI list rendering.')
示例#8
0
    def parse_locations(self, body, headers):
        """Parse OCCI Entity collection

        :param string body[]: text to parse
        :param string headers[]: headers to parse (unused in text/plain)
        :return: Array of links
        :rtype: string[]
        """
        locations = []
        for line in body:
            if not line.strip():
                continue

            matched = TextRenderer.reLocation.match(line)
            if not matched:
                raise occi.ParseError(
                    'OCCI Location expected in OCCI Entity collection', line)
            uri = matched.group(2)
            if not check_url(uri, scheme=True, host=True):
                raise occi.ParseError('Invalid URI in OCCI Entity collection',
                                      line)
            locations.append(uri)

        return locations
示例#9
0
    def parse_locations(self, body, headers):
        """Parse OCCI Entity collection

        :param string body[]: text to parse
        :param string headers[]: headers to parse
        :return: array of renderer-specific strings
        :rtype: string[]
        """
        locations = []
        for uri in body:
            if not check_url(uri, scheme=True, host=True):
                raise occi.ParseError('Invalid URI in OCCI Entity collection',
                                      uri)
            locations.append(uri)

        return locations
示例#10
0
    def parse_actions(self, body):
        """Parse OCCI Actions.

        Example::

           http://schemas.ogf.org/occi/infrastructure/compute/action#start http://schemas.ogf.org/occi/infrastructure/compute/action#stop http://schemas.ogf.org/occi/infrastructure/compute/action#restart http://schemas.ogf.org/occi/infrastructure/compute/action#suspend

        :param string body: text to parse
        :return: array of string
        :rtype: string[]
        """
        actions = TextRenderer.reSP.split(body)
        for action in actions:
            # let's require scheme and hostname in scheme URI
            if not check_url(action, scheme=True, host=True):
                raise occi.ParseError('URI expected as an action', action)
        return actions
示例#11
0
    def parse_locations(self, body, headers):
        """Parse OCCI Entity collection

        :param string body[]: text to parse (unused in text/occi)
        :param string headers[]: headers to parse
        :return: Array of links
        :rtype: string[]
        """
        locations = []
        for line in headers:
            line = line.rstrip('\r\n')
            matched = TextRenderer.reLocation.match(line)
            if not matched:
                continue
            uris_str = matched.group(2)
            uris = self.parse_header_values(uris_str)
            for uri in uris:
                if not check_url(uri, scheme=True, host=True):
                    raise occi.ParseError('Invalid URI in OCCI Entity collection', line)
                locations.append(uri)

        return locations
示例#12
0
    def parse_categories(self, body, headers):
        """Parse OCCI Category Collection

        Beware of HTTP Headers size limitations. It is better to not use 'text/occi' mimetype for transfering OCCI Category Collection.

        :param string body[]: text to parse (unused in plain/occi)
        :param string headers[]: headers to parse
        :return: Array of OCCI Categories
        :rtype: occi.Category[]
        """
        categories = []
        category_ids = set()

        for line in headers:
            line = line.rstrip('\r\n')
            matched = TextRenderer.reCategory.match(line)
            if not matched:
                continue

            line = line[matched.end():]
            #print 'CATEGORY HIT:'
            #print line
            bodies = self.parse_header_values(line)
            #print 'SPLAT BODIES:'
            #print '\n\n'.join(bodies)

            for cat_s in bodies:
                # use the helper parser function inherited from text/plain renderer
                category = TextRenderer.parse_category_body(self, cat_s)

                # check uniqueness
                key = category['term'] + category['scheme']
                if key in category_ids:
                    raise occi.ParseError('Category not unique (term "%s", scheme "%s")' % (category['term'], category['scheme']), cat_s)
                category_ids.add(key)

                categories.append(category)

        return categories
示例#13
0
    def parse_resource(self, body, header):
        """Parse OCCI Resource instance

        :param string body[]: text to parse
        :param string headers[]: headers to parse (unused in text/plain)
        :return: categories, links, and attributes
        :rtype: [occi.Category categories[], occi.Link links[], occi.Attribute attributes[]]
        """
        categories = []
        links = []
        attributes = []

        for line in body:
            if not line.strip():
                continue

            line = line.rstrip('\r\n')
            matched = TextRenderer.reCategory.match(line)
            if matched is not None:
                s = line[matched.end():]
                categories.append(self.parse_category_body(s))
                continue
            matched = TextRenderer.reLink.match(line)
            if matched is not None:
                s = line[matched.end():]
                links.append(self.parse_link_body(s))
                continue
            matched = TextRenderer.reAttribute.match(line)
            if matched is not None:
                s = line[matched.end():]
                attributes.append(self.parse_attribute_body(s))
                continue
            else:
                raise occi.ParseError(
                    'Unexpected content of OCCI Resource instance')

        return [categories, links, attributes]
示例#14
0
    def parse_link_body(self, body):
        """Parse OCCI Link body

        Example::

           </storage/0>;rel="http://schemas.ogf.org/occi/infrastructure#storage";self="/link/storagelink/compute_103_disk_0";category="http://schemas.ogf.org/occi/infrastructure#storagelink http://opennebula.org/occi/infrastructure#storagelink";occi.core.id="compute_103_disk_0";occi.core.title="ttylinux";occi.core.target="/storage/0";occi.core.source="/compute/103";occi.storagelink.deviceid="/dev/hda";occi.storagelink.state="active"

        :param string body: text to parse
        :return: OCCI Link
        :rtype: occi.Link
        """
        link = occi.Link()

        chunks = TextRenderer.reChunks.split(body)

        if not chunks[0]:
            raise occi.ParseError(
                'Invalid format of OCCI Link, URI and "rel" expected', body)

        matched = TextRenderer.reQuotedLink.match(chunks[0])
        if not matched:
            raise occi.ParseError('URI is not properly quoted in OCCI Link',
                                  body)

        link['uri'] = matched.group(1)
        if not check_url(link['uri']):
            raise occi.ParseError('URL is not valid in OCCI Link', link['uri'])

        # skip the first chunk (URI)
        for chunk in chunks[1:]:
            keyvalue = TextRenderer.reKeyValue.split(chunk, 1)

            key = keyvalue[0]
            value = keyvalue[1]
            keymatch = TextRenderer.reKeyCheck.match(key)
            if keymatch is None:
                raise occi.ParseError('Invalid characters in link property',
                                      chunk)
            valuematch = TextRenderer.reQuoted.match(value)
            # mandatory quoting
            if key in ['rel', 'self', 'category']:
                if valuematch is None:
                    raise occi.ParseError(
                        'Link value not properly quoted or unexpected EOF',
                        chunk)
            # quoting of the other attributes optional
            if valuematch is not None:
                value = valuematch.group(1)
            # sanity check: there should not be any quotes now
            if value[0] == '"' or (len(value) >= 2 and value[-1] == '"'):
                raise occi.ParseError('Unexpected quotes in OCCI Link values',
                                      chunk)

            if key == 'scheme':
                if not check_url(value):
                    raise occi.ParseError(
                        'URL is not valid in OCCI Category scheme', chunk)
                link[key] = value
            elif key in ['rel', 'category']:
                link[key] = TextRenderer.reSP.split(value)
            elif key in ['self']:
                link[key] = value
            else:
                if 'attributes' not in link:
                    link['attributes'] = collections.OrderedDict()
                link['attributes'][key] = value

        if not link.validate():
            raise occi.ParseError('Missing fields in OCCI Link', body)

        return link
示例#15
0
    def parse_category_body(self, body):
        """Parse OCCI Category body

        Example::

           entity;scheme="http://schemas.ogf.org/occi/core#";class="kind";title="entity";location="/entity/";attributes="occi.core.id{immutable required} occi.core.title"

        :param string body: text to parse
        :return: OCCI Category
        :rtype: occi.Category
        """
        category = occi.Category()

        chunks = TextRenderer.reChunks.split(body)

        if not chunks[0]:
            raise occi.ParseError('Invalid format of category, term expected',
                                  body)

        category['term'] = chunks[0]

        # skip the first chunk (category term)
        for chunk in chunks[1:]:
            keyvalue = TextRenderer.reKeyValue.split(chunk, 1)
            if len(keyvalue) != 2:
                raise occi.ParseError('Key/value pair expected in category',
                                      chunk)

            key = keyvalue[0]
            value = keyvalue[1]
            keymatch = TextRenderer.reKeyCheck.match(key)
            if keymatch is None:
                raise occi.ParseError(
                    'Invalid characters in category property', chunk)
            # every value quoted, only class has quoting optional
            valuematch = TextRenderer.reQuoted.match(value)
            if valuematch is None and key != 'class':
                raise occi.ParseError(
                    'Category value not properly quoted or unexpected EOF',
                    chunk)
            if valuematch:
                value = valuematch.group(1)
            # sanity check: there should not be any quotes now
            if value[0] == '"' or (len(value) >= 2 and value[-1] == '"'):
                raise occi.ParseError('Unexpected quotes in category', chunk)

            if key == 'location':
                if not check_url(value):
                    raise occi.ParseError(
                        'URL is not valid in OCCI Category location', chunk)
                category[key] = value
            elif key == 'scheme':
                if not check_url(value):
                    raise occi.ParseError(
                        'URL is not valid in OCCI Category scheme', chunk)
                category[key] = value
            elif key == 'attributes':
                category[key] = self.parse_attribute_defs(value)
            elif key == 'actions':
                category[key] = self.parse_actions(value)
            elif key in ['class', 'title', 'rel']:
                category[key] = value
            else:
                raise occi.ParseError('Unknown key "%s" in category' % key,
                                      chunk)

        if not category.validate():
            raise occi.ParseError('Missing fields in OCCI Category', body)

        return category