|
19 | 19 | import time |
20 | 20 | import xml.etree.ElementTree as ET |
21 | 21 | import logging |
| 22 | +import copy |
| 23 | +import gc |
22 | 24 | from redfish import redfish_logger |
23 | 25 |
|
24 | 26 | # Version info |
25 | 27 | tool_version = "1.1.2" |
26 | 28 |
|
| 29 | +# For Windows, there are restricted characters in folder names that could be used in URIs |
| 30 | +disallowed_folder_characters_win = [ ":", "*", "?", "\"", "<", ">", "|" ] |
| 31 | +folder_name_fix = False |
| 32 | +if sys.platform == "win32" or sys.platform == "cygwin": |
| 33 | + folder_name_fix = True |
| 34 | + |
27 | 35 | def main(): |
28 | 36 | """ |
29 | 37 | Main entry point for the script |
@@ -144,7 +152,11 @@ def scan_resource( redfish_obj, args, response_times, uri, is_csdl = False ): |
144 | 152 |
|
145 | 153 | # Set up the output folder |
146 | 154 | try: |
147 | | - path = os.path.join( args.Dir, uri[1:] ) |
| 155 | + path = uri[1:] |
| 156 | + if folder_name_fix: |
| 157 | + for character in disallowed_folder_characters_win: |
| 158 | + path = path.replace( character, "_" ) |
| 159 | + path = os.path.join( args.Dir, path ) |
148 | 160 | if not os.path.isdir( path ): |
149 | 161 | # Does not exist; make the directory |
150 | 162 | os.makedirs( path ) |
@@ -193,12 +205,24 @@ def scan_resource( redfish_obj, args, response_times, uri, is_csdl = False ): |
193 | 205 | save_dict["Members"].pop() |
194 | 206 | save_dict["Members@odata.count"] = len( save_dict["Members"] ) |
195 | 207 |
|
| 208 | + # The saved copy might contain URI fixes and other changes that aren't reflective of the service, but are |
| 209 | + # needed to ensure compatibility with the system creating the mockup |
| 210 | + scan_dict = copy.deepcopy( save_dict ) |
| 211 | + |
196 | 212 | # Add the copyright statement if needed |
197 | 213 | if args.Copyright: |
198 | 214 | save_dict["@Redfish.Copyright"] = args.Copyright |
199 | 215 |
|
| 216 | + # Update the payload's URIs if they need to be corrected based on allowable folder names for the system |
| 217 | + if folder_name_fix: |
| 218 | + fix_uris( save_dict ) |
| 219 | + |
200 | 220 | with open( index_path, "w", encoding = "utf-8" ) as file: |
201 | 221 | json.dump( save_dict, file, indent = 4, separators = ( ",", ": " ) ) |
| 222 | + |
| 223 | + # Deep copies of all payloads gets expensive; force garbage collection to avoid stack overflows |
| 224 | + del save_dict |
| 225 | + gc.collect() |
202 | 226 | except Exception as err: |
203 | 227 | print( "ERROR: Could not save '{}': {}".format( uri, err ) ) |
204 | 228 | print( "Attempting to save response data in error.txt..." ) |
@@ -237,7 +261,7 @@ def scan_resource( redfish_obj, args, response_times, uri, is_csdl = False ): |
237 | 261 | if is_csdl: |
238 | 262 | scan_csdl( redfish_obj, args, response_times, resource.text ) |
239 | 263 | else: |
240 | | - scan_object( redfish_obj, args, response_times, save_dict ) |
| 264 | + scan_object( redfish_obj, args, response_times, scan_dict ) |
241 | 265 | except Exception as err: |
242 | 266 | print( "ERROR: Could not scan '{}': {}".format( uri, err ) ) |
243 | 267 | return |
@@ -299,5 +323,31 @@ def scan_csdl( redfish_obj, args, response_times, csdl ): |
299 | 323 | # Scan the reference |
300 | 324 | scan_resource( redfish_obj, args, response_times, uri, is_csdl = True ) |
301 | 325 |
|
| 326 | +def fix_uris( payload ): |
| 327 | + """ |
| 328 | + Updates URIs in a payload to ensure they do not conflict with local system folder name rules |
| 329 | +
|
| 330 | + Args: |
| 331 | + payload: The payload to update |
| 332 | + """ |
| 333 | + |
| 334 | + for item in payload: |
| 335 | + # If the payload is a dictionary, inspect the properties found |
| 336 | + if isinstance( payload, dict ): |
| 337 | + # If the item is a reference, go to the resource |
| 338 | + if item == "@odata.id" or item == "Uri" or item == "Members@odata.nextLink": |
| 339 | + if isinstance( payload[item], str ): |
| 340 | + for character in disallowed_folder_characters_win: |
| 341 | + payload[item] = payload[item].replace( character, "_" ) |
| 342 | + |
| 343 | + # If the item is an object or array, scan one level deeper |
| 344 | + elif isinstance( payload[item], dict ) or isinstance( payload[item], list ): |
| 345 | + fix_uris( payload[item] ) |
| 346 | + |
| 347 | + # If the object is a list, see if the member needs to be scanned |
| 348 | + elif isinstance( payload, list ): |
| 349 | + if isinstance( item, dict ) or isinstance( item, list ): |
| 350 | + fix_uris( item ) |
| 351 | + |
302 | 352 | if __name__ == "__main__": |
303 | 353 | sys.exit( main() ) |
0 commit comments