Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Example of implementation and use of the WriteCheck flag #192

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
68 changes: 58 additions & 10 deletions redfish_interop_validator/interop.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,16 @@

import re, copy
from enum import Enum
from collections import Counter
from collections import Counter, OrderedDict

import logging
from redfish_interop_validator.redfish import getNamespaceUnversioned, getType, getNamespace
from redfish_interop_validator.traverseInterop import callResourceURI
import redfish_interop_validator.traverseInterop as traverseInterop
my_logger = logging.getLogger()
my_logger.setLevel(logging.DEBUG)

config = {'WarnRecommended': False, 'WriteCheck': False}
config = {'WarnRecommended': traverseInterop.config.get('warnrecommended'),
'WriteCheck': traverseInterop.config.get('writecheck')}

class sEnum(Enum):
FAIL = 'FAIL'
Expand Down Expand Up @@ -190,12 +191,31 @@ def findPropItemforString(propObj, itemname):
Finds an appropriate object for an item
"""
for prop in propObj.getResourceProperties():
rf_payloadName = prop.name.split(':')[-1]
if prop.find(':') != -1:
rf_payloadName = prop.name.split(':')[-1]
else:
rf_payloadName = prop
if itemname == rf_payloadName:
return prop
return None


def getPropValue(propObj, itemname):
"""
Finds an appropriate object for an item
"""
properties = propObj.getResourceProperties()
for prop in properties:
if prop.find(':') != -1:
rf_payloadName = prop.name.split(':')[-1]
if itemname == rf_payloadName:
return prop.name.split(':')[1]
elif itemname == prop:
rf_payloadName = prop
return properties[prop]
return None


def validateWriteRequirement(propObj, profile_entry, itemname):
"""
Validates if a property is WriteRequirement or not
Expand All @@ -204,20 +224,48 @@ def validateWriteRequirement(propObj, profile_entry, itemname):
permission = 'Read'
expected = "OData.Permission/ReadWrite" if profile_entry else "Any"
if not config['WriteCheck']:
paramPass = True
paramPass = sEnum.NA
return msgInterop('WriteRequirement', profile_entry, expected, permission, paramPass),\
paramPass
if profile_entry:
targetProp = findPropItemforString(propObj, itemname.replace('#', ''))
propAttr = None
propVal = None
newAttr = None
changedAttr = None
if targetProp is not None:
propAttr = targetProp.propDict.get('OData.Permissions')
if propAttr is not None:
permission = propAttr.get('EnumMember', 'Read')
propVal = getPropValue(propObj, itemname.replace('#', ''))
if propVal is not None:
match propVal:
case str():
newAttr = propVal + 'a'
case int():
newAttr = propVal + 1
case float():
newAttr = propVal + 1.1
case dict():
newAttr['Test'].append('test1')
case OrderedDict():
newAttr['Test'].append('test2')
# NOTE: Here can be write new attribute to server
# (example in pseudo code)
# if newAttr is not None:
# curl update json message using 'login & password' / 'X-AuthTocken'
# changedAttr == get value of updated Prop from server
# permission = 'Write'
paramPass = permission \
== "OData.Permission/ReadWrite"

else:
paramPass = False

# NOTE: Here can be check if newAttr is the same as the Attr retrived from the server
# (example in pseudo code)
# if changedAttr is not None and changedAttr == newAttr:
# paramPass = True
#
# else:
# paramPass = False

else:
paramPass = True

Expand Down Expand Up @@ -608,7 +656,7 @@ def validateActionRequirement(profile_entry, rf_payload_tuple, actionname):
return msgs, counts
if "@Redfish.ActionInfo" in rf_payload_item:
vallink = rf_payload_item['@Redfish.ActionInfo']
success, rf_payload_action, code, elapsed = callResourceURI(vallink)
success, rf_payload_action, code, elapsed = traverseInterop.callResourceURI(vallink)
if not success:
rf_payload_action = None

Expand Down
8 changes: 7 additions & 1 deletion redfish_interop_validator/traverseInterop.py
Original file line number Diff line number Diff line change
Expand Up @@ -413,7 +413,13 @@ def __init__(self, name: str, uri: str, jsondata: dict, typename: str, context:
self.initiated = True

def getResourceProperties(self):
allprops = self.propertyList + self.additionalList[:min(len(self.additionalList), 100)]
allprops = list
if hasattr(self, 'jsondata'):
allprops = self.jsondata
elif hasattr(self, 'propertyList'):
allprops = self.propertyList
if hasattr(self, 'additionalList'):
allprops += self.additionalList[:min(len(self.additionalList), 100)]
return allprops

@staticmethod
Expand Down
12 changes: 9 additions & 3 deletions redfish_interop_validator/validateResource.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ def validateSingleURI(URI, profile, uriName='', expectedType=None, expectedSchem
"""
# rs-assertion: 9.4.1
# Initial startup here
interop.config['WarnRecommended'] = traverseInterop.config['warnrecommended']
interop.config['WriteCheck'] = traverseInterop.config['writecheck']

counts = Counter()
results, messages = {}, []

Expand Down Expand Up @@ -218,11 +221,14 @@ def getURIfromOdata(property):
if '/redfish/v1' in property or urlCheck.match(property):
return property
return None

def validateURITree(URI, profile, uriName, expectedType=None, expectedSchema=None, expectedJson=None):
"""name
Validates a Tree of URIs, traversing from the first given
"""
interop.config['WarnRecommended'] = traverseInterop.config['warnrecommended']
interop.config['WriteCheck'] = traverseInterop.config['writecheck']

allLinks = set()
allLinks.add(URI.rstrip('/'))
refLinks = list()
Expand All @@ -243,7 +249,7 @@ def validateURITree(URI, profile, uriName, expectedType=None, expectedSchema=Non
SchemaType = getType(resource_obj.jsondata.get('@odata.type', 'NoType'))
resource_stats[SchemaType] = {
"Exists": True,
"Writeable": False,
"Writeable": traverseInterop.config['writecheck'],
"URIsFound": [URI.rstrip('/')],
"SubordinateTo": set(),
"UseCasesFound": set()
Expand Down Expand Up @@ -307,7 +313,7 @@ def validateURITree(URI, profile, uriName, expectedType=None, expectedSchema=Non
if resource_stats.get(SchemaType) is None:
resource_stats[SchemaType] = {
"Exists": True,
"Writeable": False,
"Writeable": traverseInterop.config['writecheck'],
"URIsFound": [link.rstrip('/')],
"SubordinateTo": set([tuple(reversed(subordinate_tree))]),
"UseCasesFound": set(usecases_found),
Expand Down