Skip to content

Commit 9f1ac11

Browse files
committed
Example of implementation and use of the WriteCheck flag
- Example of passing an using the WarnCheck flag in code - Adding sEnum "NA" - Modification of the findPropItemforString method - Adding the getPropValue method - Sets default result value of property on N/A when WriteCheck flag is off - Sets default result value of property on False when WriteCheck flag is on - Example of updating property of resource. - Comment with an example of logic for updating the resource and checking whether the operation was successful, written in pseudocode.
1 parent 2d84492 commit 9f1ac11

File tree

3 files changed

+76
-15
lines changed

3 files changed

+76
-15
lines changed

redfish_interop_validator/interop.py

+60-11
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,24 @@
55

66
import re, copy
77
from enum import Enum
8-
from collections import Counter
8+
from collections import Counter, OrderedDict
99

1010
import logging
1111
from redfish_interop_validator.redfish import getNamespaceUnversioned, getType, getNamespace
12-
from redfish_interop_validator.traverseInterop import callResourceURI
12+
import redfish_interop_validator.traverseInterop as traverseInterop
1313
my_logger = logging.getLogger()
1414
my_logger.setLevel(logging.DEBUG)
1515

16-
config = {'WarnRecommended': False, 'WriteCheck': False}
16+
config = {'WarnRecommended': traverseInterop.config.get('warnrecommended'),
17+
'WriteCheck': traverseInterop.config.get('writecheck')}
1718

1819
class sEnum(Enum):
1920
FAIL = 'FAIL'
2021
NOPASS = 'NO PASS'
2122
PASS = 'PASS'
2223
WARN = 'WARN'
2324
OK = 'OK'
25+
NA = 'N/A'
2426

2527
REDFISH_ABSENT = 'n/a'
2628

@@ -180,12 +182,31 @@ def findPropItemforString(propObj, itemname):
180182
Finds an appropriate object for an item
181183
"""
182184
for prop in propObj.getResourceProperties():
183-
rf_payloadName = prop.name.split(':')[-1]
185+
if prop.find(':') != -1:
186+
rf_payloadName = prop.name.split(':')[-1]
187+
else:
188+
rf_payloadName = prop
184189
if itemname == rf_payloadName:
185190
return prop
186191
return None
187192

188193

194+
def getPropValue(propObj, itemname):
195+
"""
196+
Finds an appropriate object for an item
197+
"""
198+
properties = propObj.getResourceProperties()
199+
for prop in properties:
200+
if prop.find(':') != -1:
201+
rf_payloadName = prop.name.split(':')[-1]
202+
if itemname == rf_payloadName:
203+
return prop.name.split(':')[1]
204+
elif itemname == prop:
205+
rf_payloadName = prop
206+
return properties[prop]
207+
return None
208+
209+
189210
def validateWriteRequirement(propObj, profile_entry, itemname):
190211
"""
191212
Validates if a property is WriteRequirement or not
@@ -194,20 +215,48 @@ def validateWriteRequirement(propObj, profile_entry, itemname):
194215
permission = 'Read'
195216
expected = "OData.Permission/ReadWrite" if profile_entry else "Any"
196217
if not config['WriteCheck']:
197-
paramPass = True
218+
paramPass = sEnum.NA
198219
return msgInterop('WriteRequirement', profile_entry, expected, permission, paramPass),\
199220
paramPass
200221
if profile_entry:
201222
targetProp = findPropItemforString(propObj, itemname.replace('#', ''))
202-
propAttr = None
223+
propVal = None
224+
newAttr = None
225+
changedAttr = None
203226
if targetProp is not None:
204-
propAttr = targetProp.propDict.get('OData.Permissions')
205-
if propAttr is not None:
206-
permission = propAttr.get('EnumMember', 'Read')
227+
propVal = getPropValue(propObj, itemname.replace('#', ''))
228+
if propVal is not None:
229+
match propVal:
230+
case str():
231+
newAttr = propVal + 'a'
232+
case int():
233+
newAttr = propVal + 1
234+
case float():
235+
newAttr = propVal + 1.1
236+
case dict():
237+
newAttr['Test'].append('test1')
238+
case OrderedDict():
239+
newAttr['Test'].append('test2')
240+
# NOTE: Here can be write new attribute to server
241+
# (example in pseudo code)
242+
# if newAttr is not None:
243+
# curl update json message using 'login & password' / 'X-AuthTocken'
244+
# changedAttr == get value of updated Prop from server
245+
# permission = 'Write'
207246
paramPass = permission \
208247
== "OData.Permission/ReadWrite"
248+
209249
else:
210250
paramPass = False
251+
252+
# NOTE: Here can be check if newAttr is the same as the Attr retrived from the server
253+
# (example in pseudo code)
254+
# if changedAttr is not None and changedAttr == newAttr:
255+
# paramPass = True
256+
#
257+
# else:
258+
# paramPass = False
259+
211260
else:
212261
paramPass = True
213262

@@ -249,7 +298,7 @@ def checkComparison(val, compareType, target):
249298
paramPass = len(alltarget) == len(target)
250299
if compareType == "LinkToResource":
251300
vallink = val.get('@odata.id')
252-
success, rf_payload, code, elapsed = callResourceURI(vallink)
301+
success, rf_payload, code, elapsed = traverseInterop.callResourceURI(vallink)
253302
if success:
254303
ourType = rf_payload.get('@odata.type')
255304
if ourType is not None:
@@ -595,7 +644,7 @@ def validateActionRequirement(profile_entry, rf_payload_tuple, actionname):
595644
return msgs, counts
596645
if "@Redfish.ActionInfo" in rf_payload_item:
597646
vallink = rf_payload_item['@Redfish.ActionInfo']
598-
success, rf_payload_action, code, elapsed = callResourceURI(vallink)
647+
success, rf_payload_action, code, elapsed = traverseInterop.callResourceURI(vallink)
599648
if not success:
600649
rf_payload_action = None
601650

redfish_interop_validator/traverseInterop.py

+7-1
Original file line numberDiff line numberDiff line change
@@ -413,7 +413,13 @@ def __init__(self, name: str, uri: str, jsondata: dict, typename: str, context:
413413
self.initiated = True
414414

415415
def getResourceProperties(self):
416-
allprops = self.propertyList + self.additionalList[:min(len(self.additionalList), 100)]
416+
allprops = list
417+
if hasattr(self, 'jsondata'):
418+
allprops = self.jsondata
419+
elif hasattr(self, 'propertyList'):
420+
allprops = self.propertyList
421+
if hasattr(self, 'additionalList'):
422+
allprops += self.additionalList[:min(len(self.additionalList), 100)]
417423
return allprops
418424

419425
@staticmethod

redfish_interop_validator/validateResource.py

+9-3
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ def validateSingleURI(URI, profile, uriName='', expectedType=None, expectedSchem
5252
"""
5353
# rs-assertion: 9.4.1
5454
# Initial startup here
55+
interop.config['WarnRecommended'] = traverseInterop.config['warnrecommended']
56+
interop.config['WriteCheck'] = traverseInterop.config['writecheck']
57+
5558
counts = Counter()
5659
results, messages = {}, []
5760

@@ -218,11 +221,14 @@ def getURIfromOdata(property):
218221
if '/redfish/v1' in property or urlCheck.match(property):
219222
return property
220223
return None
221-
224+
222225
def validateURITree(URI, profile, uriName, expectedType=None, expectedSchema=None, expectedJson=None):
223226
"""name
224227
Validates a Tree of URIs, traversing from the first given
225228
"""
229+
interop.config['WarnRecommended'] = traverseInterop.config['warnrecommended']
230+
interop.config['WriteCheck'] = traverseInterop.config['writecheck']
231+
226232
allLinks = set()
227233
allLinks.add(URI.rstrip('/'))
228234
refLinks = list()
@@ -243,7 +249,7 @@ def validateURITree(URI, profile, uriName, expectedType=None, expectedSchema=Non
243249
SchemaType = getType(resource_obj.jsondata.get('@odata.type', 'NoType'))
244250
resource_stats[SchemaType] = {
245251
"Exists": True,
246-
"Writeable": False,
252+
"Writeable": traverseInterop.config['writecheck'],
247253
"URIsFound": [URI.rstrip('/')],
248254
"SubordinateTo": set(),
249255
"UseCasesFound": set()
@@ -307,7 +313,7 @@ def validateURITree(URI, profile, uriName, expectedType=None, expectedSchema=Non
307313
if resource_stats.get(SchemaType) is None:
308314
resource_stats[SchemaType] = {
309315
"Exists": True,
310-
"Writeable": False,
316+
"Writeable": traverseInterop.config['writecheck'],
311317
"URIsFound": [link.rstrip('/')],
312318
"SubordinateTo": set([tuple(reversed(subordinate_tree))]),
313319
"UseCasesFound": set(usecases_found),

0 commit comments

Comments
 (0)