Exemplo n.º 1
0
def validateMinVersion(version, entry):
    """
    Checks for the minimum version of a resource's type
    """
    rsvLogger.debug('Testing minVersion \n\t' + str((version, entry)))
    # If version doesn't contain version as is, try it as v#_#_#
    entry_split = entry.split('.')
    # get version from payload
    if (re.match('#([a-zA-Z0-9_.-]*\.)+[a-zA-Z0-9_.-]*', version) is not None):
        v_payload = rst.getNamespace(version).split('.', 1)[-1]
        v_payload = v_payload.replace('v', '')
        if ('_' in v_payload):
            payload_split = v_payload.split('_')
        else:
            payload_split = v_payload.split('.')
    else:
        payload_split = version.split('.')

    paramPass = True
    for a, b in zip(entry_split, payload_split):
        b = 0 if b is None else b
        a = 0 if a is None else a
        if (b > a):
            break
        if (b < a):
            paramPass = False
            break

    # use string comparison, given version numbering is accurate to regex
    rsvLogger.debug('\tpass ' + str(paramPass))
    return msgInterop('MinVersion', '{} ({})'.format(entry, payload_split), '<=', version, paramPass),\
        paramPass
Exemplo n.º 2
0
def validateMinVersion(fulltype, entry):
    """
    Checks for the minimum version of a resource's type
    """
    fulltype = fulltype.replace('#', '')
    rsvLogger.info('Testing minVersion \n\t' + str((fulltype, entry)))
    # If fulltype doesn't contain version as is, try it as v#_#_#
    versionSplit = entry.split('.')
    versionNew = 'v'
    for x in versionSplit:
        versionNew = versionNew + x + '_'
    versionNew = versionNew[:-1]
    # get version from payload
    v_payload = rst.getNamespace(fulltype).split('.', 1)[-1]
    # use string comparison, given version numbering is accurate to regex
    paramPass = v_payload >= (versionNew if 'v' in v_payload else entry)
    rsvLogger.info('\tpass ' + str(paramPass))
    if not paramPass:
        rsvLogger.error('\tNo Pass')
    return msgInterop('MinVersion', '{} ({})'.format(entry, versionNew), '<=', fulltype, paramPass),\
        paramPass
Exemplo n.º 3
0
def validateSingleURI(URI,
                      uriName='',
                      expectedType=None,
                      expectedSchema=None,
                      expectedJson=None,
                      parent=None):
    # rs-assertion: 9.4.1
    # Initial startup here
    lc = setupLoggingCaptures()
    next(lc)
    # Start
    rsvLogger.verboseout("\n*** %s, %s", uriName, URI)
    rsvLogger.info("\n*** %s", URI)
    rsvLogger.debug("\n*** %s, %s, %s", expectedType, expectedSchema
                    is not None, expectedJson is not None)
    counts = Counter()
    results = OrderedDict()
    messages = OrderedDict()

    results[uriName] = {
        'uri': URI,
        'success': False,
        'counts': counts,
        'messages': messages,
        'errors': '',
        'warns': '',
        'rtime': '',
        'context': '',
        'fulltype': '',
        'rcode': 0,
        'payload': {}
    }

    # check for @odata mandatory stuff
    # check for version numbering problems
    # check id if its the same as URI
    # check @odata.context instead of local.  Realize that @odata is NOT a "property"

    # Attempt to get a list of properties
    if URI is None:
        if parent is not None:
            parentURI = parent.uri
        else:
            parentURI = 'MissingParent'
        URI = parentURI + '/Missing URI Link'
        rsvLogger.warning(
            'Tool appears to be missing vital URI information, replacing URI w/: {}'
            .format(URI))
    # Generate dictionary of property info
    try:
        if expectedJson is None:
            success, jsondata, status, rtime = rst.callResourceURI(URI)
            results[uriName]['payload'] = jsondata
        else:
            results[uriName]['payload'] = expectedJson

        # verify basic odata strings
        if results[uriName]['payload'] is not None:
            successPayload, odataMessages = rst.ResourceObj.checkPayloadConformance(
                results[uriName]['payload'], URI)
            messages.update(odataMessages)

        propResourceObj = rst.createResourceObject(uriName, URI, expectedJson,
                                                   expectedType,
                                                   expectedSchema, parent)
        if not propResourceObj:
            counts['problemResource'] += 1
            results[uriName]['warns'], results[uriName]['errors'] = next(lc)
            return False, counts, results, None, None
    except AuthenticationError as e:
        raise  # re-raise exception
    except Exception as e:
        rsvLogger.debug('Exception caught while creating ResourceObj',
                        exc_info=1)
        rsvLogger.error('Unable to gather property info for URI {}: {}'.format(
            URI, repr(e)))
        counts['exceptionResource'] += 1
        results[uriName]['warns'], results[uriName]['errors'] = next(lc)
        return False, counts, results, None, None
    counts['passGet'] += 1

    # verify odata_id properly resolves to its parent if holding fragment
    odata_id = propResourceObj.jsondata.get('@odata.id', 'void')
    if '#' in odata_id:
        if parent is not None:
            payload_resolve = rst.navigateJsonFragment(parent.jsondata, URI)
            if payload_resolve is None:
                rsvLogger.error(
                    '@odata.id of ReferenceableMember does not contain a valid JSON pointer for this payload: {}'
                    .format(odata_id))
                counts['badOdataIdResolution'] += 1
            elif payload_resolve != propResourceObj.jsondata:
                rsvLogger.error(
                    '@odata.id of ReferenceableMember does not point to the correct object: {}'
                    .format(odata_id))
                counts['badOdataIdResolution'] += 1
        else:
            rsvLogger.warn(
                'No parent found with which to test @odata.id of ReferenceableMember'
            )

    if not successPayload:
        counts['failPayloadError'] += 1
        rsvLogger.error(
            str(URI) + ': payload error, @odata property non-conformant', )

    # if URI was sampled, get the notation text from rst.uri_sample_map
    sample_string = rst.uri_sample_map.get(URI)
    sample_string = sample_string + ', ' if sample_string is not None else ''

    results[uriName]['uri'] = (str(URI))
    results[uriName]['samplemapped'] = (str(sample_string))
    results[uriName]['rtime'] = propResourceObj.rtime
    results[uriName]['rcode'] = propResourceObj.status
    results[uriName]['payload'] = propResourceObj.jsondata
    results[uriName]['context'] = propResourceObj.context
    results[uriName]['origin'] = propResourceObj.schemaObj.origin
    results[uriName]['fulltype'] = propResourceObj.typename
    results[uriName]['success'] = True

    rsvLogger.info("\t Type (%s), GET SUCCESS (time: %s)",
                   propResourceObj.typename, propResourceObj.rtime)

    # If this is an AttributeRegistry, load it for later use
    if isinstance(propResourceObj.jsondata, dict):
        odata_type = propResourceObj.jsondata.get('@odata.type')
        if odata_type is not None:
            namespace = odata_type.split('.')[0]
            type_name = odata_type.split('.')[-1]
            if namespace == '#AttributeRegistry' and type_name == 'AttributeRegistry':
                loadAttributeRegDict(odata_type, propResourceObj.jsondata)

    for prop in propResourceObj.getResourceProperties():
        try:
            if not prop.valid and not prop.exists:
                continue
            propMessages, propCounts = checkPropertyConformance(
                propResourceObj.schemaObj,
                prop.name,
                prop,
                propResourceObj.jsondata,
                parentURI=URI)
            if '@Redfish.Copyright' in propMessages and 'MessageRegistry' not in propResourceObj.typeobj.fulltype:
                modified_entry = list(propMessages['@Redfish.Copyright'])
                modified_entry[-1] = 'FAIL'
                propMessages['@Redfish.Copyright'] = tuple(modified_entry)
                rsvLogger.error(
                    '@Redfish.Copyright is only allowed for mockups, and should not be allowed in official implementations'
                )
            if prop.payloadName != prop.propChild:
                propCounts['invalidName'] += 1
                for propMsg in propMessages:
                    modified_entry = list(propMessages[propMsg])
                    modified_entry[-1] = 'Invalid'
                    propMessages[propMsg] = tuple(modified_entry)
            if not prop.valid:
                rsvLogger.error(
                    'Verifying property that does not belong to this version: {}'
                    .format(prop.name))
                for propMsg in propMessages:
                    propCounts['invalidEntry'] += 1
                    modified_entry = list(propMessages[propMsg])
                    modified_entry[-1] = 'Invalid'
                    propMessages[propMsg] = tuple(modified_entry)

            messages.update(propMessages)
            counts.update(propCounts)
        except AuthenticationError as e:
            raise  # re-raise exception
        except Exception as ex:
            rsvLogger.debug('Exception caught while validating single URI',
                            exc_info=1)
            rsvLogger.error(
                '{}: Could not finish check on this property ({})'.format(
                    prop.name, str(ex)))
            counts['exceptionPropCheck'] += 1

    uriName, SchemaFullType, jsonData = propResourceObj.name, propResourceObj.typeobj.fulltype, propResourceObj.jsondata
    SchemaNamespace, SchemaType = rst.getNamespace(
        SchemaFullType), rst.getType(SchemaFullType)

    # List all items checked and unchecked
    # current logic does not check inside complex types
    fmt = '%-30s%30s'
    rsvLogger.verboseout('%s, %s, %s', uriName, SchemaNamespace, SchemaType)

    for key in jsonData:
        item = jsonData[key]
        rsvLogger.verboseout(fmt % (key, messages[key][3] if key in messages
                                    else 'Exists, no schema check'))

    allowAdditional = propResourceObj.typeobj.additional
    for key in [
            k for k in jsonData
            if k not in messages and k not in propResourceObj.unknownProperties
    ] + propResourceObj.unknownProperties:
        # note: extra messages for "unchecked" properties
        if not allowAdditional:
            rsvLogger.error(
                '{} not defined in schema {} (check version, spelling and casing)'
                .format(key, SchemaNamespace))
            counts['failAdditional'] += 1
            messages[key] = (displayValue(item), '-', '-', 'FAIL')
        else:
            rsvLogger.warn(
                '{} not defined in schema {} (check version, spelling and casing)'
                .format(key, SchemaNamespace))
            counts['unverifiedAdditional'] += 1
            messages[key] = (displayValue(item), '-', '-', 'Additional')

    for key in messages:
        if key not in jsonData:
            rsvLogger.verboseout(fmt % (key, messages[key][3]))

    results[uriName]['warns'], results[uriName]['errors'] = next(lc)

    pass_val = len(results[uriName]['errors']) == 0
    for key in counts:
        if any(x in key for x in ['problem', 'fail', 'bad', 'exception']):
            pass_val = False
            break
    rsvLogger.info("\t {}".format('PASS' if pass_val else ' FAIL...'))

    rsvLogger.verboseout('%s, %s', SchemaFullType, counts)

    # Get all links available

    rsvLogger.debug(propResourceObj.links)

    return True, counts, results, propResourceObj.links, propResourceObj
Exemplo n.º 4
0
def validateSingleURI(URI,
                      profile,
                      uriName='',
                      expectedType=None,
                      expectedSchema=None,
                      expectedJson=None,
                      parent=None):
    """
    Validates a single URI that is given, returning its ResourceObject, counts and links
    """
    # rs-assertion: 9.4.1
    # Initial startup here
    lc = setupLoggingCaptures()
    next(lc)

    # Start
    counts = Counter()
    results = OrderedDict()
    messages = []

    results[uriName] = {
        'uri': URI,
        'success': False,
        'counts': counts,
        'messages': messages,
        'errors': '',
        'warns': '',
        'rtime': '',
        'context': '',
        'fulltype': ''
    }

    # check for @odata mandatory stuff
    # check for version numbering problems
    # check id if its the same as URI
    # check @odata.context instead of local.  Realize that @odata is NOT a "property"

    # Attempt to get a list of properties
    if URI is None:
        if parent is not None:
            parentURI = parent.uri
        else:
            parentURI = '...'
        URI = parentURI + '...'
    if expectedJson is None:
        successGet, jsondata, status, rtime = rst.callResourceURI(URI)
    else:
        successGet, jsondata = True, expectedJson

    if jsondata is not None:
        successPayload, odataMessages = rst.ResourceObj.checkPayloadConformance(
            jsondata, URI)

        if not successPayload:
            counts['failPayloadWarn'] += 1
            rsvLogger.verboseout(
                str(URI) + ': payload error, @odata property non-conformant', )

    # Generate dictionary of property info
    try:
        propResourceObj = rst.createResourceObject(uriName, URI, expectedJson,
                                                   expectedType,
                                                   expectedSchema, parent)
        if not propResourceObj:
            counts['problemResource'] += 1
            results[uriName]['warns'], results[uriName]['errors'] = next(lc)
            return False, counts, results, None, None
    except AuthenticationError:
        raise  # re-raise exception
    except Exception:
        rsvLogger.exception("")
        counts['exceptionResource'] += 1
        results[uriName]['warns'], results[uriName]['errors'] = next(lc)
        return False, counts, results, None, None

    counts['passGet'] += 1

    # if URI was sampled, get the notation text from rst.uri_sample_map
    sample_string = rst.uri_sample_map.get(URI)
    sample_string = sample_string + ', ' if sample_string is not None else ''

    results[uriName]['uri'] = (str(URI))
    results[uriName]['samplemapped'] = (str(sample_string))
    results[uriName]['rtime'] = propResourceObj.rtime
    results[uriName]['context'] = propResourceObj.context
    results[uriName]['origin'] = propResourceObj.schemaObj.origin
    results[uriName]['fulltype'] = propResourceObj.typeobj.fulltype
    results[uriName]['success'] = True

    rsvLogger.debug("\t URI {}, Type ({}), GET SUCCESS (time: {})".format(
        URI, propResourceObj.typeobj.stype, propResourceObj.rtime))

    uriName, SchemaFullType, jsondata = propResourceObj.name, propResourceObj.typeobj.fulltype, propResourceObj.jsondata
    SchemaNamespace, SchemaType = rst.getNamespace(
        SchemaFullType), rst.getType(SchemaFullType)

    objRes = profile.get('Resources')

    if SchemaType not in objRes:
        rsvLogger.debug('\nNo Such Type in sample {} {}.{}, skipping'.format(
            URI, SchemaNamespace, SchemaType))
    else:
        rsvLogger.info("\n*** %s, %s", URI, SchemaType)
        rsvLogger.debug("\n*** %s, %s, %s", expectedType, expectedSchema
                        is not None, expectedJson is not None)
        objRes = objRes.get(SchemaType)
        try:
            propMessages, propCounts = commonInterop.validateInteropResource(
                propResourceObj, objRes, jsondata)
            messages = messages.extend(propMessages)
            counts.update(propCounts)
            rsvLogger.info('{} of {} tests passed.'.format(
                counts['pass'] + counts['warn'], counts['totaltests']))
        except Exception:
            rsvLogger.exception("Something went wrong")
            rsvLogger.error(
                'Could not finish validation check on this payload')
            counts['exceptionProfilePayload'] += 1
        rsvLogger.info('%s, %s\n', SchemaFullType, counts)

    # Get all links available
    results[uriName]['warns'], results[uriName]['errors'] = next(lc)

    rsvLogger.debug(propResourceObj.links)
    return True, counts, results, propResourceObj.links, propResourceObj
Exemplo n.º 5
0
def validateEntity(name: str,
                   val: dict,
                   propType: str,
                   propCollectionType: str,
                   schemaObj,
                   autoExpand,
                   parentURI=""):
    """
    Validates an entity based on its uri given
    """
    rsvLogger.debug('validateEntity: name = {}'.format(name))

    # check for required @odata.id
    if '@odata.id' not in val:
        if autoExpand:
            default = parentURI + '#/{}'.format(
                name.replace('[', '/').strip(']'))
        else:
            default = parentURI + '/{}'.format(name)
        rsvLogger.error(
            "{}: EntityType resource does not contain required @odata.id property, attempting default {}"
            .format(name, default))
        if parentURI == "":
            return False
        uri = default
    else:
        uri = val['@odata.id']
    # check if the entity is truly what it's supposed to be
    paramPass = False
    # if not autoexpand, we must grab the resource
    if not autoExpand:
        success, data, status, delay = rst.callResourceURI(uri)
    else:
        success, data, status, delay = True, val, 200, 0
    rsvLogger.debug(
        '(success, uri, status, delay) = {}, (propType, propCollectionType) = {}, data = {}'
        .format((success, uri, status, delay), (propType, propCollectionType),
                data))
    # if the reference is a Resource, save us some trouble as most/all basetypes are Resource
    generics = [
        'Resource.ItemOrCollection', 'Resource.ResourceCollection',
        'Resource.Item', 'Resource.Resource'
    ]
    if (propCollectionType in generics or propType in generics) and success:
        return True
    elif success:
        # Attempt to grab an appropriate type to test against and its schema
        # Default lineup: payload type, collection type, property type
        currentType = data.get('@odata.type', propCollectionType)
        if currentType is None:
            currentType = propType
        soup, refs = schemaObj.soup, schemaObj.refs
        baseLink = refs.get(
            rst.getNamespace(propCollectionType
                             if propCollectionType is not None else propType))
        # if schema in current schema, then use it
        #   elif namespace in References, use that
        #   else we have no lead
        if soup.find('Schema',
                     attrs={'Namespace':
                            rst.getNamespace(currentType)}) is not None:
            success, baseObj = True, schemaObj
        elif baseLink is not None:
            baseObj = schemaObj.getSchemaFromReference(
                rst.getNamespaceUnversioned(currentType))
            success = baseObj is not None
        else:
            success = False

        if not success:
            rsvLogger.error(
                "Schema of target {} not referenced in current resource, concluding type {} is not of expected type {}"
                .format(uri, currentType, propType))
        rsvLogger.debug('success = {}, currentType = {}, baseLink = {}'.format(
            success, currentType, baseLink))

        # Recurse through parent types, gather type hierarchy to check against
        if success and currentType is not None and baseObj.getTypeTagInSchema(
                currentType) is None and success:
            rsvLogger.error(
                '{}: Linked resource reports version {} not in Schema {}'.
                format(name.split(':')[-1], currentType, baseObj.origin))

        elif success and currentType is not None:
            currentType = currentType.replace('#', '')
            allTypes = []
            while currentType not in allTypes and success:
                allTypes.append(currentType)
                success, baseObj, currentType = baseObj.getParentType(
                    currentType, 'EntityType')
                rsvLogger.debug('success = {}, currentType = {}'.format(
                    success, currentType))

            rsvLogger.debug(
                'propType = {}, propCollectionType = {}, allTypes = {}'.format(
                    propType, propCollectionType, allTypes))
            paramPass = propType in allTypes or propCollectionType in allTypes
            if not paramPass:
                full_namespace = propCollectionType if propCollectionType is not None else propType
                rsvLogger.error(
                    '{}: Linked resource reports schema version (or namespace): {} not found in typechain'
                    .format(name.split(':')[-1], full_namespace))
        else:
            rsvLogger.error(
                "{}: Could not get schema file for Entity check".format(name))
    else:
        if "OriginOfCondition" in name:
            rsvLogger.verboseout(
                "{}: GET of resource at URI {} returned HTTP {}, but was a temporary resource."
                .format(
                    name, uri, status
                    if isinstance(status, int) and status >= 200 else "error"))
            return True

        else:
            rsvLogger.error(
                "{}: GET of resource at URI {} returned HTTP {}. Check URI.".
                format(
                    name, uri, status
                    if isinstance(status, int) and status >= 200 else "error"))
    return paramPass