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