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