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