xref: /openbmc/bmcweb/scripts/update_schemas.py (revision 63faafa5)
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
15SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__))
16
17proxies = {
18    'https': os.environ.get("https_proxy", None)
19}
20
21r = requests.get('https://www.dmtf.org/sites/default/files/standards/documents/'
22                 'DSP8010_2018.3.zip', proxies=proxies)
23
24r.raise_for_status()
25
26static_path = os.path.realpath(os.path.join(SCRIPT_DIR, "..", "static",
27                                            "redfish", "v1"))
28
29schema_path = os.path.join(static_path, "schema")
30json_schema_path = os.path.join(static_path, "JsonSchemas")
31metadata_index_path = os.path.join(static_path, "$metadata", "index.xml")
32
33zipBytesIO = BytesIO(r.content)
34zip_ref = zipfile.ZipFile(zipBytesIO)
35
36# Remove the old files
37if os.path.exists(schema_path):
38    files = glob.glob(os.path.join(schema_path, '[!Oem]*'))
39    for f in files:
40        os.remove(f)
41if os.path.exists(json_schema_path):
42    files = glob.glob(os.path.join(json_schema_path, '[!Oem]*'))
43    for f in files:
44        if (os.path.isfile(f)):
45            os.remove(f)
46        else:
47            shutil.rmtree(f)
48os.remove(metadata_index_path)
49
50if not os.path.exists(schema_path):
51    os.makedirs(schema_path)
52if not os.path.exists(json_schema_path):
53    os.makedirs(json_schema_path)
54
55with open(metadata_index_path, 'w') as metadata_index:
56
57    metadata_index.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
58    metadata_index.write(
59        "<edmx:Edmx xmlns:edmx=\"http://docs.oasis-open.org/odata/ns/edmx\" Version=\"4.0\">\n")
60
61    for zip_filepath in zip_ref.namelist():
62        if zip_filepath.startswith('DSP8010_2018.3/csdl/') & (zip_filepath != "DSP8010_2018.3/csdl/"):
63            filename = os.path.basename(zip_filepath)
64            with open(os.path.join(schema_path, filename), 'wb') as schema_file:
65
66                metadata_index.write(
67                    "    <edmx:Reference Uri=\"/redfish/v1/schema/" + filename + "\">\n")
68
69                content = zip_ref.read(zip_filepath)
70                xml_root = ET.fromstring(content)
71
72                for edmx_child in xml_root:
73
74                    if edmx_child.tag == "{http://docs.oasis-open.org/odata/ns/edmx}DataServices":
75                        for data_child in edmx_child:
76                            if data_child.tag == "{http://docs.oasis-open.org/odata/ns/edm}Schema":
77                                namespace = data_child.attrib["Namespace"]
78                                if namespace.startswith("RedfishExtensions"):
79                                    metadata_index.write(
80                                        "        <edmx:Include Namespace=\"" + namespace + "\"  Alias=\"Redfish\"/>\n")
81
82                                else:
83                                    metadata_index.write(
84                                        "        <edmx:Include Namespace=\"" + namespace + "\"/>\n")
85                schema_file.write(content)
86                metadata_index.write("    </edmx:Reference>\n")
87
88    metadata_index.write("""    <edmx:DataServices>
89        <Schema xmlns="http://docs.oasis-open.org/odata/ns/edm" Namespace="Service">
90            <EntityContainer Name="Service" Extends="ServiceRoot.v1_0_0.ServiceContainer"/>
91        </Schema>
92    </edmx:DataServices>
93""")
94    #TODO:Issue#32 There's a bug in the script that currently deletes this
95    #schema (because it's an OEM schema). Because it's the only one, and we
96    #don't update schemas very often, we just manually fix it. Need a
97    #permanent fix to the script.
98    metadata_index.write("    <edmx:Reference Uri=\"/redfish/v1/schema/OemManager_v1.xml\"/>\n")
99    metadata_index.write("        <edmx:Include Namespace=\"OemManager\"/>\n")
100    metadata_index.write("    </edmx:Reference>\n")
101    metadata_index.write("</edmx:Edmx>\n")
102
103schema_files = {}
104for zip_filepath in zip_ref.namelist():
105    if zip_filepath.startswith('DSP8010_2018.3/json-schema/'):
106        filename = os.path.basename(zip_filepath)
107        filenamesplit = filename.split(".")
108        if len(filenamesplit) == 3:
109            thisSchemaVersion = schema_files.get(filenamesplit[0], None)
110            if thisSchemaVersion == None:
111                schema_files[filenamesplit[0]] = filenamesplit[1]
112            else:
113                # need to see if we're a newer version.
114                if list(map(int, filenamesplit[1][1:].split("_"))) > list(map(
115                        int, thisSchemaVersion[1:].split("_"))):
116                    schema_files[filenamesplit[0]] = filenamesplit[1]
117
118
119for schema, version in schema_files.items():
120    basename = schema + "." + version + ".json"
121    zip_filepath = os.path.join("DSP8010_2018.3/json-schema", basename)
122    schemadir = os.path.join(json_schema_path, schema)
123    os.makedirs(schemadir)
124    location_json = OrderedDict()
125    location_json["Language"] = "en"
126    location_json["PublicationUri"] = (
127        "http://redfish.dmtf.org/schemas/v1/" + schema + ".json")
128    location_json["Uri"] = (
129        "/redfish/v1/JsonSchemas/" + schema + "/" + schema + ".json")
130
131    index_json = OrderedDict()
132    index_json["@odata.context"] = "/redfish/v1/$metadata#JsonSchemaFile.JsonSchemaFile"
133    index_json["@odata.id"] = "/redfish/v1/JsonSchemas/" + schema
134    index_json["@odata.type"] = "#JsonSchemaFile.v1_0_2.JsonSchemaFile"
135    index_json["Name"] = schema + " Schema File"
136    index_json["Schema"] = "#" + schema + "." + schema
137    index_json["Description"] =  schema + " Schema File Location"
138    index_json["Id"] = schema
139    index_json["Languages"] = [ "en" ]
140    index_json["Languages@odata.count"] = 1
141    index_json["Location"] = [ location_json ]
142    index_json["Location@odata.count"] = 1
143
144    with open(os.path.join(schemadir, "index.json"), 'w') as schema_file:
145        json.dump(index_json, schema_file, indent=4)
146    with open(os.path.join(schemadir, schema + ".json"), 'wb') as schema_file:
147        schema_file.write(zip_ref.read(zip_filepath))
148
149with open(os.path.join(json_schema_path, "index.json"), 'w') as index_file:
150    members = [{"@odata.id": "/redfish/v1/JsonSchemas/" + schema + "/"}
151               for schema in schema_files]
152
153    members.sort(key=lambda x: x["@odata.id"])
154
155    indexData = OrderedDict()
156
157    indexData["@odata.id"] = "/redfish/v1/JsonSchemas"
158    indexData["@odata.context"] = ("/redfish/v1/$metadata"
159                                   "#JsonSchemaFileCollection."
160                                   "JsonSchemaFileCollection")
161    indexData["@odata.type"] = ("#JsonSchemaFileCollection."
162                                "JsonSchemaFileCollection")
163    indexData["Name"] = "JsonSchemaFile Collection"
164    indexData["Description"] = "Collection of JsonSchemaFiles"
165    indexData["Members@odata.count"] = len(schema_files)
166    indexData["Members"] = members
167
168    json.dump(indexData, index_file, indent=2)
169
170zip_ref.close()
171