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
12import subprocess
13
14import xml.etree.ElementTree as ET
15
16REGISTRY_HEADER = '''
17/****************************************************************
18 * This is an auto-generated header which contains definitions
19 * for Redfish DMTF defined messages.
20 ***************************************************************/
21#pragma once
22#include <registries.hpp>
23
24namespace redfish::message_registries::{}
25{{
26'''
27
28SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__))
29
30include_path = os.path.realpath(
31    os.path.join(
32        SCRIPT_DIR,
33        "..",
34        "redfish-core",
35        "include",
36        "registries"))
37
38proxies = {
39    'https': os.environ.get("https_proxy", None)
40}
41
42
43def make_getter(dmtf_name, header_name, type_name):
44    url = 'https://redfish.dmtf.org/registries/{}'.format(dmtf_name)
45    dmtf = requests.get(url, proxies=proxies)
46    dmtf.raise_for_status()
47    json_file = json.loads(dmtf.text)
48    path = os.path.join(include_path, header_name)
49    return (path, json_file, type_name, url)
50
51
52def clang_format(filename):
53    subprocess.check_call(["clang-format-12", "-i", filename])
54
55
56files = []
57files.append(make_getter('Base.1.10.0.json',
58                         'base_message_registry.hpp',
59                         'base'))
60files.append(make_getter('TaskEvent.1.0.3.json',
61                         'task_event_message_registry.hpp',
62                         'task_event'))
63files.append(make_getter('ResourceEvent.1.0.3.json',
64                         'resource_event_message_registry.hpp',
65                         'resource_event'))
66
67# Remove the old files
68for file, json_dict, namespace, url in files:
69    try:
70        os.remove(file)
71    except BaseException:
72        print("{} not found".format(file))
73
74    with open(file, 'w') as registry:
75        registry.write(REGISTRY_HEADER.format(namespace))
76        # Parse the Registry header info
77        registry.write("const Header header = {")
78        registry.write("\"{}\",".format(json_dict["@Redfish.Copyright"]))
79        registry.write("\"{}\",".format(json_dict["@odata.type"]))
80        registry.write("\"{}\",".format(json_dict["Id"]))
81        registry.write("\"{}\",".format(json_dict["Name"]))
82        registry.write("\"{}\",".format(json_dict["Language"]))
83        registry.write("\"{}\",".format(json_dict["Description"]))
84        registry.write("\"{}\",".format(json_dict["RegistryPrefix"]))
85        registry.write("\"{}\",".format(json_dict["RegistryVersion"]))
86        registry.write("\"{}\",".format(json_dict["OwningEntity"]))
87        registry.write("};")
88
89        registry.write('constexpr const char * url = "{}";\n\n'.format(url))
90        # Parse each Message entry
91        registry.write(
92            "constexpr std::array<MessageEntry, {}> registry = {{".format(
93                len(json_dict["Messages"])))
94        for messageId, message in sorted(json_dict["Messages"].items()):
95            registry.write("MessageEntry{")
96            registry.write("\"{}\",".format(messageId))
97            registry.write("{")
98            registry.write("\"{}\",".format(message["Description"]))
99            registry.write("\"{}\",".format(message["Message"]))
100            registry.write("\"{}\",".format(message["Severity"]))
101            registry.write("\"{}\",".format(message["MessageSeverity"]))
102            registry.write("{},".format(message["NumberOfArgs"]))
103            registry.write("{")
104            paramTypes = message.get("ParamTypes")
105            if paramTypes:
106                for paramType in paramTypes:
107                    registry.write("\"{}\",".format(paramType))
108            registry.write("},")
109            registry.write("\"{}\",".format(message["Resolution"]))
110            registry.write("}},")
111        registry.write("};}\n")
112    clang_format(file)
113
114
115def get_privilege_string_from_list(privilege_list):
116    privilege_string = "{{\n"
117    for privilege_json in privilege_list:
118        privileges = privilege_json["Privilege"]
119        privilege_string += "    {"
120        for privilege in privileges:
121            if privilege == "NoAuth":
122                continue
123            privilege_string += "\""
124            privilege_string += privilege
125            privilege_string += "\",\n"
126        if privilege != "NoAuth":
127            privilege_string = privilege_string[:-2]
128        privilege_string += "}"
129        privilege_string += ",\n"
130    privilege_string = privilege_string[:-2]
131    privilege_string += "\n}}"
132    return privilege_string
133
134
135def get_variable_name_for_privilege_set(privilege_list):
136    names = []
137    for privilege_json in privilege_list:
138        privileges = privilege_json["Privilege"]
139        names.append("And".join(privileges))
140    return "Or".join(names)
141
142
143def make_privilege_registry():
144    path, json_file, type_name, url = \
145        make_getter('Redfish_1.1.0_PrivilegeRegistry.json',
146                    'privilege_registry.hpp', 'privilege')
147    with open(path, 'w') as registry:
148        registry.write("#pragma once\n")
149        registry.write(
150            "//{} is generated.  Do not edit directly\n".format(
151                os.path.basename(path)))
152
153        registry.write("#include <privileges.hpp>\n\n")
154        registry.write("namespace redfish::privileges{\n")
155
156        privilege_dict = {}
157        for mapping in json_file["Mappings"]:
158            # first pass, identify all the unique privilege sets
159            for operation, privilege_list in mapping["OperationMap"].items():
160                privilege_dict[get_privilege_string_from_list(
161                    privilege_list)] = (privilege_list, )
162        registry.write("// clang-format off\n")
163        for index, key in enumerate(privilege_dict):
164            (privilege_list, ) = privilege_dict[key]
165            name = get_variable_name_for_privilege_set(privilege_list)
166            registry.write(
167                "const std::array<Privileges, {}> ".format(
168                    len(privilege_list)))
169            registry.write(
170                "privilegeSet{} = {};\n".format(name, key))
171            privilege_dict[key] = (privilege_list, name)
172        registry.write("// clang-format on\n\n")
173
174        for mapping in json_file["Mappings"]:
175            entity = mapping["Entity"]
176            registry.write("//{}\n".format(entity))
177            for operation, privilege_list in mapping["OperationMap"].items():
178                privilege_string = get_privilege_string_from_list(
179                    privilege_list)
180                operation = operation.lower()
181
182                registry.write(
183                    "const static auto& {}{} = privilegeSet{};\n".format(
184                        operation,
185                        entity,
186                        privilege_dict[privilege_string][1]))
187            registry.write("\n")
188        registry.write("} // namespace redfish::privileges\n")
189    clang_format(path)
190
191
192make_privilege_registry()
193