1#!/usr/bin/python3 2import requests 3import zipfile 4from io import BytesIO 5import os 6from collections import OrderedDict 7import shutil 8import json 9 10import xml.etree.ElementTree as ET 11 12VERSION = "DSP8010_2021.2" 13 14# To use a new schema, add to list and rerun tool 15include_list = [ 16 'AccountService', 17 'ActionInfo', 18 'Assembly', 19 'AttributeRegistry', 20 'Bios', 21 'Certificate', 22 'CertificateCollection', 23 'CertificateLocations', 24 'CertificateService', 25 'Chassis', 26 'ChassisCollection', 27 'ComputerSystem', 28 'ComputerSystemCollection', 29 'Drive', 30 'DriveCollection', 31 'EthernetInterface', 32 'EthernetInterfaceCollection', 33 'Event', 34 'EventDestination', 35 'EventDestinationCollection', 36 'EventService', 37 'IPAddresses', 38 'JsonSchemaFile', 39 'JsonSchemaFileCollection', # redfish/v1/JsonSchemas 40 'LogEntry', 41 'LogEntryCollection', 42 'LogService', 43 'LogServiceCollection', 44 'Manager', 45 'ManagerAccount', 46 'ManagerAccountCollection', 47 'ManagerCollection', 48 'ManagerNetworkProtocol', 49 'Memory', 50 'MemoryCollection', 51 'Message', 52 'MessageRegistry', 53 'MessageRegistryCollection', 54 'MessageRegistryFile', 55 'MessageRegistryFileCollection', 56 'MetricDefinition', 57 'MetricDefinitionCollection', 58 'MetricReport', 59 'MetricReportCollection', 60 'MetricReportDefinition', 61 'MetricReportDefinitionCollection', 62 'OperatingConfig', 63 'OperatingConfigCollection', 64 'PCIeDevice', 65 'PCIeDeviceCollection', 66 'PCIeFunction', 67 'PCIeFunctionCollection', 68 'Power', 69 'Privileges', # Used in Role 70 'Processor', 71 'ProcessorCollection', 72 'RedfishError', 73 'RedfishExtensions', 74 'Redundancy', 75 'Resource', 76 'Role', 77 'RoleCollection', 78 'Sensor', 79 'SensorCollection', 80 'ServiceRoot', 81 'Session', 82 'SessionCollection', 83 'SessionService', 84 'Settings', 85 'SoftwareInventory', 86 'SoftwareInventoryCollection', 87 'Storage', 88 'StorageCollection', 89 'StorageController', 90 'StorageControllerCollection', 91 'Task', 92 'TaskCollection', 93 'TaskService', 94 'TelemetryService', 95 'Thermal', 96 'UpdateService', 97 'VLanNetworkInterfaceCollection', 98 'VLanNetworkInterface', 99 'VirtualMedia', 100 'VirtualMediaCollection', 101 'odata', 102 'odata-v4', 103 'redfish-error', 104 'redfish-payload-annotations', 105 'redfish-schema', 106 'redfish-schema-v1', 107] 108 109SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__)) 110 111proxies = { 112 'https': os.environ.get("https_proxy", None) 113} 114 115r = requests.get( 116 'https://www.dmtf.org/sites/default/files/standards/documents/' + 117 VERSION + 118 '.zip', 119 proxies=proxies) 120 121r.raise_for_status() 122 123static_path = os.path.realpath(os.path.join(SCRIPT_DIR, "..", "static", 124 "redfish", "v1")) 125 126schema_path = os.path.join(static_path, "schema") 127json_schema_path = os.path.join(static_path, "JsonSchemas") 128metadata_index_path = os.path.join(static_path, "$metadata", "index.xml") 129 130zipBytesIO = BytesIO(r.content) 131zip_ref = zipfile.ZipFile(zipBytesIO) 132 133# Remove the old files 134skip_prefixes = ('Oem') 135if os.path.exists(schema_path): 136 files = [os.path.join(schema_path, f) for f in os.listdir(schema_path) 137 if not f.startswith(skip_prefixes)] 138 for f in files: 139 os.remove(f) 140if os.path.exists(json_schema_path): 141 files = [os.path.join(json_schema_path, f) for f in 142 os.listdir(json_schema_path) if not f.startswith(skip_prefixes)] 143 for f in files: 144 if (os.path.isfile(f)): 145 os.remove(f) 146 else: 147 shutil.rmtree(f) 148os.remove(metadata_index_path) 149 150if not os.path.exists(schema_path): 151 os.makedirs(schema_path) 152if not os.path.exists(json_schema_path): 153 os.makedirs(json_schema_path) 154 155with open(metadata_index_path, 'w') as metadata_index: 156 157 metadata_index.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n") 158 metadata_index.write( 159 "<edmx:Edmx xmlns:edmx=" 160 "\"http://docs.oasis-open.org/odata/ns/edmx\"" 161 " Version=\"4.0\">\n") 162 163 for zip_filepath in zip_ref.namelist(): 164 if zip_filepath.startswith(VERSION + '/' + VERSION + '/csdl/') and \ 165 (zip_filepath != VERSION + "/csdl/") and \ 166 (zip_filepath != VERSION + '/' + VERSION + "/csdl/"): 167 filename = os.path.basename(zip_filepath) 168 169 # filename looks like Zone_v1.xml 170 filenamesplit = filename.split("_") 171 if filenamesplit[0] not in include_list: 172 print("excluding schema: " + filename) 173 continue 174 175 with open(os.path.join(schema_path, filename), 'wb') as schema_out: 176 177 metadata_index.write( 178 " <edmx:Reference Uri=\"/redfish/v1/schema/" + 179 filename + 180 "\">\n") 181 182 content = zip_ref.read(zip_filepath) 183 content = content.replace(b'\r\n', b'\n') 184 xml_root = ET.fromstring(content) 185 edmx = "{http://docs.oasis-open.org/odata/ns/edmx}" 186 edm = "{http://docs.oasis-open.org/odata/ns/edm}" 187 for edmx_child in xml_root: 188 if edmx_child.tag == edmx + "DataServices": 189 for data_child in edmx_child: 190 if data_child.tag == edm + "Schema": 191 namespace = data_child.attrib["Namespace"] 192 if namespace.startswith("RedfishExtensions"): 193 metadata_index.write( 194 " " 195 "<edmx:Include Namespace=\"" + 196 namespace + 197 "\" Alias=\"Redfish\"/>\n" 198 ) 199 200 else: 201 metadata_index.write( 202 " " 203 "<edmx:Include Namespace=\"" 204 + namespace + "\"/>\n" 205 ) 206 schema_out.write(content) 207 metadata_index.write(" </edmx:Reference>\n") 208 209 metadata_index.write(" <edmx:DataServices>\n" 210 " <Schema " 211 "xmlns=\"http://docs.oasis-open.org/odata/ns/edm\" " 212 "Namespace=\"Service\">\n" 213 " <EntityContainer Name=\"Service\" " 214 "Extends=\"ServiceRoot.v1_0_0.ServiceContainer\"/>\n" 215 " </Schema>\n" 216 " </edmx:DataServices>\n" 217 ) 218 # TODO:Issue#32 There's a bug in the script that currently deletes this 219 # schema (because it's an OEM schema). Because it's the only six, and we 220 # don't update schemas very often, we just manually fix it. Need a 221 # permanent fix to the script. 222 metadata_index.write( 223 " <edmx:Reference Uri=\"/redfish/v1/schema/OemManager_v1.xml\">\n") 224 metadata_index.write(" <edmx:Include Namespace=\"OemManager\"/>\n") 225 metadata_index.write(" </edmx:Reference>\n") 226 227 metadata_index.write( 228 " <edmx:Reference Uri=\"" 229 "/redfish/v1/schema/OemComputerSystem_v1.xml\">\n") 230 metadata_index.write( 231 " <edmx:Include Namespace=\"OemComputerSystem\"/>\n") 232 metadata_index.write(" </edmx:Reference>\n") 233 234 metadata_index.write( 235 " <edmx:Reference Uri=\"" 236 "/redfish/v1/schema/OemVirtualMedia_v1.xml\">\n") 237 metadata_index.write( 238 " <edmx:Include Namespace=\"OemVirtualMedia\"/>\n") 239 metadata_index.write( 240 " <edmx:Include Namespace=\"OemVirtualMedia.v1_0_0\"/>\n") 241 metadata_index.write(" </edmx:Reference>\n") 242 243 metadata_index.write( 244 " <edmx:Reference Uri=\"" 245 "/redfish/v1/schema/OemAccountService_v1.xml\">\n") 246 metadata_index.write( 247 " <edmx:Include Namespace=\"OemAccountService\"/>\n") 248 metadata_index.write( 249 " <edmx:Include Namespace=\"OemAccountService.v1_0_0\"/>\n") 250 metadata_index.write(" </edmx:Reference>\n") 251 252 metadata_index.write( 253 " <edmx:Reference Uri=\"/redfish/v1/schema/OemSession_v1.xml\">\n") 254 metadata_index.write(" <edmx:Include Namespace=\"OemSession\"/>\n") 255 metadata_index.write( 256 " <edmx:Include Namespace=\"OemSession.v1_0_0\"/>\n") 257 metadata_index.write(" </edmx:Reference>\n") 258 259 metadata_index.write("</edmx:Edmx>\n") 260 261schema_files = {} 262for zip_filepath in zip_ref.namelist(): 263 if zip_filepath.startswith(os.path.join(VERSION, VERSION, 'json-schema/')): 264 filename = os.path.basename(zip_filepath) 265 filenamesplit = filename.split(".") 266 267 # exclude schemas again to save flash space 268 if filenamesplit[0] not in include_list: 269 continue 270 271 if len(filenamesplit) == 3: 272 thisSchemaVersion = schema_files.get(filenamesplit[0], None) 273 if thisSchemaVersion is None: 274 schema_files[filenamesplit[0]] = filenamesplit[1] 275 else: 276 # need to see if we're a newer version. 277 if list(map(int, filenamesplit[1][1:].split("_"))) > list(map( 278 int, thisSchemaVersion[1:].split("_"))): 279 schema_files[filenamesplit[0]] = filenamesplit[1] 280 281 282for schema, version in schema_files.items(): 283 basename = schema + "." + version + ".json" 284 zip_filepath = os.path.join(VERSION, VERSION, "json-schema", basename) 285 schemadir = os.path.join(json_schema_path, schema) 286 os.makedirs(schemadir) 287 location_json = OrderedDict() 288 location_json["Language"] = "en" 289 location_json["PublicationUri"] = ( 290 "http://redfish.dmtf.org/schemas/v1/" + schema + ".json") 291 location_json["Uri"] = ( 292 "/redfish/v1/JsonSchemas/" + schema + "/" + schema + ".json") 293 294 index_json = OrderedDict() 295 index_json["@odata.context"] = \ 296 "/redfish/v1/$metadata#JsonSchemaFile.JsonSchemaFile" 297 index_json["@odata.id"] = "/redfish/v1/JsonSchemas/" + schema 298 index_json["@odata.type"] = "#JsonSchemaFile.v1_0_2.JsonSchemaFile" 299 index_json["Name"] = schema + " Schema File" 300 index_json["Schema"] = "#" + schema + "." + schema 301 index_json["Description"] = schema + " Schema File Location" 302 index_json["Id"] = schema 303 index_json["Languages"] = ["en"] 304 index_json["Languages@odata.count"] = 1 305 index_json["Location"] = [location_json] 306 index_json["Location@odata.count"] = 1 307 308 with open(os.path.join(schemadir, "index.json"), 'w') as schema_file: 309 json.dump(index_json, schema_file, indent=4) 310 with open(os.path.join(schemadir, schema + ".json"), 'wb') as schema_file: 311 schema_file.write(zip_ref.read(zip_filepath).replace(b'\r\n', b'\n')) 312 313with open(os.path.join(json_schema_path, "index.json"), 'w') as index_file: 314 members = [{"@odata.id": "/redfish/v1/JsonSchemas/" + schema} 315 for schema in schema_files] 316 317 members.sort(key=lambda x: x["@odata.id"]) 318 319 indexData = OrderedDict() 320 321 indexData["@odata.id"] = "/redfish/v1/JsonSchemas" 322 indexData["@odata.context"] = ("/redfish/v1/$metadata" 323 "#JsonSchemaFileCollection." 324 "JsonSchemaFileCollection") 325 indexData["@odata.type"] = ("#JsonSchemaFileCollection." 326 "JsonSchemaFileCollection") 327 indexData["Name"] = "JsonSchemaFile Collection" 328 indexData["Description"] = "Collection of JsonSchemaFiles" 329 indexData["Members@odata.count"] = len(schema_files) 330 indexData["Members"] = members 331 332 json.dump(indexData, index_file, indent=2) 333 334zip_ref.close() 335