def __init__(self,
                 schemaObj,
                 propOwner,
                 propChild,
                 val,
                 topVersion=None,
                 customType=None,
                 payloadName=None):
        try:
            self.name = propOwner + ':' + propChild
            self.propOwner, self.propChild = propOwner, propChild
            self.val = val
            self.valid = topVersion is None or \
                    (getNamespaceUnversioned(propOwner) in topVersion and getNamespace(propOwner) <= topVersion)\
                    or getNamespaceUnversioned(propOwner) not in topVersion
            self.exists = val != 'n/a'
            self.payloadName = payloadName if payloadName is not None else propChild
            self.propDict = getPropertyDetails(schemaObj, propOwner, propChild,
                                               val, topVersion, customType)
            self.attr = self.propDict['attrs']

        except Exception as ex:
            rst.traverseLogger.debug(
                'Exception caught while creating new PropItem', exc_info=1)
            rst.traverseLogger.error(
                '{}:{} :  Could not get details on this property ({})'.format(
                    str(propOwner), str(propChild), str(ex)))
            self.propDict = None
            self.attr = None
            return
        pass
Exemple #2
0
    def __init__(self,
                 schemaObj,
                 propOwner,
                 propChild,
                 val,
                 topVersion=None,
                 customType=None,
                 payloadName=None,
                 versionList=None,
                 parent=None,
                 top_of_resource=None):
        try:
            self.name = propOwner + ':' + propChild
            self.propOwner, self.propChild = propOwner, propChild
            self.val = val
            highest_version_of_payload = [1, 0, 0]
            sub_valid = True
            if isinstance(val, dict) and '@odata.type' in val:
                highest_version_of_payload = splitVersionString(
                    getNamespace(val['@odata.type']))
            elif top_of_resource is not None:
                highest_version_of_payload = splitVersionString(
                    getNamespace(top_of_resource.typename))
                sub_valid = getNamespaceUnversioned(
                    propOwner) != getNamespaceUnversioned(
                        top_of_resource.typename)
            self.valid = sub_valid or\
                    topVersion is None or\
                    versionList is None or\
                    (getNamespace( propOwner ) in versionList) or\
                    (splitVersionString(propOwner) <= splitVersionString(topVersion)) or\
                    (splitVersionString(propOwner) <= (highest_version_of_payload))

            self.exists = val != 'n/a'
            self.payloadName = payloadName if payloadName is not None else propChild
            self.propDict = getPropertyDetails(schemaObj,
                                               propOwner,
                                               propChild,
                                               val,
                                               topVersion,
                                               customType,
                                               parent=parent,
                                               top_of_resource=top_of_resource)
            self.attr = self.propDict['attrs']

        except Exception as ex:
            rst.traverseLogger.debug(
                'Exception caught while creating new PropItem', exc_info=1)
            rst.traverseLogger.error(
                '{}:{} :  Could not get details on this property ({})'.format(
                    str(propOwner), str(propChild), str(ex)))
            self.propDict = None
            self.attr = None
            return
        pass
    def getHighestType(self, acquiredtype: str, limit=None):
        """getHighestType

        get Highest possible version for given type

        :param acquiredtype: Type available
        :param limit: Version string limit (full namespace or just version 'v1_x_x')
        """
        typelist = list()

        if limit is not None:
            if getVersion(limit) is None:
                rst.traverseLogger.warning('Limiting namespace has no version, erasing: {}'.format(limit))
                limit = None
            else:
                limit = getVersion(limit)

        for schema in self.soup.find_all('Schema'):
            newNamespace = schema.get('Namespace')
            if limit is not None:
                if getVersion(newNamespace) is None:
                    continue
                if compareMinVersion(newNamespace, limit):
                    continue
            if schema.find(['EntityType', 'ComplexType'], attrs={'Name': getType(acquiredtype)}, recursive=False):
                typelist.append(splitVersionString(newNamespace))

        if len(typelist) > 1:
            for ns in reversed(sorted(typelist)):
                rst.traverseLogger.debug(
                    "{}   {}".format(ns, getType(acquiredtype)))
                acquiredtype = getNamespaceUnversioned(acquiredtype) + '.v{}_{}_{}'.format(*ns) + '.' + getType(acquiredtype)
                return acquiredtype
        return acquiredtype
def getTypeObject(typename, schemaObj):
    idtag = (typename, schemaObj.origin)
    if idtag in PropType.robjcache:
        return PropType.robjcache[idtag]

    typename = typename.strip('#')
    if schemaObj.getTypeTagInSchema(typename) is None:
        if schemaObj.getTypeTagInSchema(getNamespaceUnversioned(typename)) is None:
            rst.traverseLogger.error("getTypeObject: Namespace appears nonexistent in SchemaXML: {} {}".format(typename, schemaObj.origin))
            return None

    acquiredtype = schemaObj.getHighestType(typename)
    if acquiredtype != typename:
        return getTypeObject(acquiredtype, schemaObj)
    else:
        newType = PropType(typename, schemaObj)
        PropType.robjcache[idtag] = newType
        return newType
Exemple #5
0
def getSchemaDetailsLocal(SchemaType, SchemaURI):
    """
    Find Schema file for given Namespace, from local directory

    param SchemaType: Schema Namespace, such as ServiceRoot
    param SchemaURI: uri to grab schem (generate information from it)
    return: (success boolean, a Soup object, origin)
    """
    Alias = getNamespaceUnversioned(SchemaType)
    config = rst.config
    SchemaLocation, SchemaSuffix = config['metadatafilepath'], config[
        'schemasuffix']
    if SchemaURI is not None:
        uriparse = SchemaURI.split('/')[-1].split('#')
        xml = uriparse[0]
    else:
        rst.traverseLogger.warning(
            "SchemaURI was empty, must generate xml name from type {}".format(
                SchemaType)),
        return getSchemaDetailsLocal(SchemaType, Alias + SchemaSuffix)
    rst.traverseLogger.debug(
        (SchemaType, SchemaURI, SchemaLocation + '/' + xml))
    filestring = Alias + SchemaSuffix if xml is None else xml
    try:
        # get file
        with open(SchemaLocation + '/' + xml, "r") as filehandle:
            data = filehandle.read()

        # get tags
        soup = BeautifulSoup(data, "xml")
        edmxTag = soup.find('edmx:Edmx', recursive=False)
        parentTag = edmxTag.find('edmx:DataServices', recursive=False)
        child = parentTag.find('Schema', recursive=False)
        SchemaNamespace = child['Namespace']
        FoundAlias = SchemaNamespace.split(".")[0]
        rst.traverseLogger.debug(FoundAlias)

        if '/redfish/v1/$metadata' in SchemaURI:
            if len(uriparse) > 1:
                frag = getNamespace(SchemaType)
                frag = frag.split('.', 1)[0]
                refType, refLink = getReferenceDetails(soup,
                                                       name=SchemaLocation +
                                                       '/' + filestring).get(
                                                           frag, (None, None))
                if refLink is not None:
                    rst.traverseLogger.debug(
                        'Entering {} inside {}, pulled from $metadata'.format(
                            refType, refLink))
                    return getSchemaDetails(refType, refLink)
                else:
                    rst.traverseLogger.error(
                        'Could not find item in $metadata {}'.format(frag))
                    return False, None, None
            else:
                return True, soup, "localFile:" + SchemaLocation + '/' + filestring

        if FoundAlias in Alias:
            return True, soup, "localFile:" + SchemaLocation + '/' + filestring

    except FileNotFoundError:
        # if we're looking for $metadata locally... ditch looking for it, go straight to file
        if '/redfish/v1/$metadata' in SchemaURI and Alias != '$metadata':
            rst.traverseLogger.warning(
                "Unable to find a harddrive stored $metadata at {}, defaulting to {}"
                .format(SchemaLocation, Alias + SchemaSuffix))
            return getSchemaDetailsLocal(SchemaType, Alias + SchemaSuffix)
        else:
            rst.traverseLogger.warn
            ("Schema file {} not found in {}".format(filestring,
                                                     SchemaLocation))
            if Alias == '$metadata':
                rst.traverseLogger.warning(
                    "If $metadata cannot be found, Annotations may be unverifiable"
                )
    except Exception as ex:
        rst.traverseLogger.error(
            "A problem when getting a local schema has occurred {}".format(
                SchemaURI))
        rst.traverseLogger.warning("output: ", exc_info=True)
    return False, None, None
def createResourceObject(name,
                         uri,
                         jsondata=None,
                         typename=None,
                         context=None,
                         parent=None,
                         isComplex=False):
    """
    Factory for resource object, move certain work here
    """
    traverseLogger.debug('Creating ResourceObject {} {} {}'.format(
        name, uri, typename))
    oem = config.get('oemcheck', True)

    # Create json from service or from given
    original_jsondata = jsondata
    if jsondata is None and not isComplex:
        success, jsondata, status, rtime = callResourceURI(uri)
        traverseLogger.debug('{}, {}, {}'.format(success, jsondata, status))
        if not success:
            traverseLogger.error('{}:  URI could not be acquired: {}'.format(
                uri, status))
            return None
    else:
        success, jsondata, status, rtime = True, jsondata, -1, 0

    if not isinstance(jsondata, dict):
        if not isComplex:
            traverseLogger.error("Resource no longer a dictionary...")
        else:
            traverseLogger.debug("ComplexType does not have val")
        return success, None, status
        return None

    acquiredtype = jsondata.get('@odata.type', typename)
    if acquiredtype is None:
        traverseLogger.error(
            '{}:  Json does not contain @odata.type or NavType'.format(uri))
        return None

    if typename is not None:
        if not oem and 'OemObject' in typename:
            acquiredtype = typename

    original_context = context
    if context is None:
        context = jsondata.get('@odata.context')
        if context is None:
            context = createContext(acquiredtype)

    # Get Schema object
    schemaObj = rfSchema.getSchemaObject(acquiredtype, context)
    if schemaObj is None:
        traverseLogger.warn(
            "ResourceObject creation: No schema XML for {} {}".format(
                acquiredtype, context))
        return None

    forceType = False
    # Check if this is a Registry resource
    parent_type = parent.typename if parent is not None and parent.typeobj is not None else None

    # get highest type if type is invalid
    if schemaObj.getTypeTagInSchema(acquiredtype) is None:
        if schemaObj.getTypeTagInSchema(
                getNamespaceUnversioned(acquiredtype)) is not None:
            traverseLogger.warn(
                "Namespace version of type appears missing from SchemaXML, attempting highest type: {}"
                .format(acquiredtype))
            acquiredtype = schemaObj.getHighestType(acquiredtype, parent_type)
            typename = acquiredtype
            traverseLogger.warn("New namespace: {}".format(typename))
            forceType = True
        else:
            traverseLogger.warn(
                "getResourceObject: Namespace appears nonexistent in SchemaXML: {} {}"
                .format(acquiredtype, context))
            return None

    # check odata.id if it corresponds
    odata_id = jsondata.get('@odata.id', '')

    currentType = acquiredtype
    baseObj = schemaObj
    success = True
    allTypes = []
    while currentType not in allTypes and success:
        allTypes.append(currentType)
        success, baseObj, currentType = baseObj.getParentType(
            currentType, 'EntityType')
        traverseLogger.debug('success = {}, currentType = {}'.format(
            success, currentType))

    uri_item = uri
    scheme, netloc, path, params, query, fragment = urlparse(uri_item)
    scheme, netloc, path, params, query, fragment_odata = urlparse(odata_id)

    if 'Resource.Resource' in allTypes:
        if fragment is '':
            if original_jsondata is None:
                traverseLogger.debug(
                    'Acquired resource OK {}'.format(uri_item))
            else:
                traverseLogger.debug(
                    'Acquired resource thru AutoExpanded means {}'.format(
                        uri_item))
                traverseLogger.info(
                    'Regetting resource from URI {}'.format(uri_item))
                new_payload = createResourceObject(name, uri_item, None,
                                                   typename, context, parent,
                                                   isComplex)
                if new_payload is None:
                    traverseLogger.warn(
                        'Could not acquire resource, reverting to original payload...'
                    )
        else:
            if original_jsondata is None:
                traverseLogger.warn(
                    'Acquired Resource.Resource type with fragment, could cause issues  {}'
                    .format(uri_item))
            else:
                traverseLogger.warn(
                    'Found uri with fragment, which Resource.Resource types do not use {}'
                    .format(uri_item))
        if fragment_odata is '':
            pass
        else:
            traverseLogger.warn(
                '@odata.id should not have a fragment'.format(odata_id))

    elif 'Resource.ReferenceableMember' in allTypes:
        if fragment is not '':
            pass
        else:
            traverseLogger.warn(
                'No fragment, but ReferenceableMembers require it {}'.format(
                    uri_item))
        if fragment_odata is not '':
            pass
        else:
            traverseLogger.warn(
                '@odata.id should have a fragment'.format(odata_id))

    newResource = ResourceObj(name,
                              uri,
                              jsondata,
                              typename,
                              original_context,
                              parent,
                              isComplex,
                              forceType=forceType)
    newResource.rtime = rtime
    newResource.status = status

    return newResource