xref: /openbmc/bmcweb/scripts/update_schemas.py (revision 9d424669)
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