1#!/usr/bin/env python3
2import json
3import os
4
5import requests
6
7WARNING = '''/****************************************************************
8 *                 READ THIS WARNING FIRST
9 * This is an auto-generated header which contains definitions
10 * for Redfish DMTF defined messages.
11 * DO NOT modify this registry outside of running the
12 * parse_registries.py script.  The definitions contained within
13 * this file are owned by DMTF.  Any modifications to these files
14 * should be first pushed to the relevant registry in the DMTF
15 * github organization.
16 ***************************************************************/'''
17
18REGISTRY_HEADER = WARNING + '''
19#pragma once
20#include <registries.hpp>
21
22// clang-format off
23
24namespace redfish::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
52files = []
53files.append(make_getter('Base.1.13.0.json',
54                         'base_message_registry.hpp',
55                         'base'))
56files.append(make_getter('TaskEvent.1.0.3.json',
57                         'task_event_message_registry.hpp',
58                         'task_event'))
59files.append(make_getter('ResourceEvent.1.0.3.json',
60                         'resource_event_message_registry.hpp',
61                         'resource_event'))
62
63# Remove the old files
64for file, json_dict, namespace, url in files:
65    try:
66        os.remove(file)
67    except BaseException:
68        print("{} not found".format(file))
69
70    with open(file, 'w') as registry:
71        registry.write(REGISTRY_HEADER.format(namespace))
72        # Parse the Registry header info
73        registry.write(
74            "const Header header = {{\n"
75            "    \"{json_dict[@Redfish.Copyright]}\",\n"
76            "    \"{json_dict[@odata.type]}\",\n"
77            "    \"{json_dict[Id]}\",\n"
78            "    \"{json_dict[Name]}\",\n"
79            "    \"{json_dict[Language]}\",\n"
80            "    \"{json_dict[Description]}\",\n"
81            "    \"{json_dict[RegistryPrefix]}\",\n"
82            "    \"{json_dict[RegistryVersion]}\",\n"
83            "    \"{json_dict[OwningEntity]}\",\n"
84            "}};\n"
85            "constexpr const char* url =\n"
86            "    \"{url}\";\n"
87            "\n"
88            "constexpr std::array registry =\n"
89            "{{\n".format(
90                json_dict=json_dict,
91                url=url,
92            ))
93
94        messages_sorted = sorted(json_dict["Messages"].items())
95        for messageId, message in messages_sorted:
96            registry.write(
97                "    MessageEntry{{\n"
98                "        \"{messageId}\",\n"
99                "        {{\n"
100                "            \"{message[Description]}\",\n"
101                "            \"{message[Message]}\",\n"
102                "            \"{message[MessageSeverity]}\",\n"
103                "            {message[NumberOfArgs]},\n"
104                "            {{".format(
105                    messageId=messageId,
106                    message=message
107                ))
108            paramTypes = message.get("ParamTypes")
109            if paramTypes:
110                for paramType in paramTypes:
111                    registry.write(
112                        "\n"
113                        "                \"{}\",".format(paramType)
114                    )
115                registry.write("\n            },\n")
116            else:
117                registry.write("},\n")
118            registry.write(
119                "            \"{message[Resolution]}\",\n"
120                "        }}}},\n".format(message=message))
121
122        registry.write(
123            "\n};\n"
124            "\n"
125            "enum class Index\n"
126            "{\n"
127        )
128        for index, (messageId, message) in enumerate(messages_sorted):
129            messageId = messageId[0].lower() + messageId[1:]
130            registry.write(
131                "    {} = {},\n".format(messageId, index))
132        registry.write(
133            "}};\n"
134            "}} // namespace redfish::registries::{}\n"
135            .format(namespace))
136
137
138def get_privilege_string_from_list(privilege_list):
139    privilege_string = "{{\n"
140    for privilege_json in privilege_list:
141        privileges = privilege_json["Privilege"]
142        privilege_string += "    {"
143        for privilege in privileges:
144            if privilege == "NoAuth":
145                continue
146            privilege_string += "\""
147            privilege_string += privilege
148            privilege_string += "\",\n"
149        if privilege != "NoAuth":
150            privilege_string = privilege_string[:-2]
151        privilege_string += "}"
152        privilege_string += ",\n"
153    privilege_string = privilege_string[:-2]
154    privilege_string += "\n}}"
155    return privilege_string
156
157
158def get_variable_name_for_privilege_set(privilege_list):
159    names = []
160    for privilege_json in privilege_list:
161        privileges = privilege_json["Privilege"]
162        names.append("And".join(privileges))
163    return "Or".join(names)
164
165
166def make_privilege_registry():
167    path, json_file, type_name, url = \
168        make_getter('Redfish_1.3.0_PrivilegeRegistry.json',
169                    'privilege_registry.hpp', 'privilege')
170    with open(path, 'w') as registry:
171        registry.write(
172            "#pragma once\n"
173            "{WARNING}\n"
174            "// clang-format off\n"
175            "\n"
176            "#include <privileges.hpp>\n"
177            "\n"
178            "namespace redfish::privileges\n"
179            "{{\n"
180            .format(
181                WARNING=WARNING,
182                filename=os.path.basename(path)))
183
184        privilege_dict = {}
185        for mapping in json_file["Mappings"]:
186            # first pass, identify all the unique privilege sets
187            for operation, privilege_list in mapping["OperationMap"].items():
188                privilege_dict[get_privilege_string_from_list(
189                    privilege_list)] = (privilege_list, )
190        for index, key in enumerate(privilege_dict):
191            (privilege_list, ) = privilege_dict[key]
192            name = get_variable_name_for_privilege_set(privilege_list)
193            registry.write(
194                "const std::array<Privileges, {length}> "
195                "privilegeSet{name} = {key};\n"
196                .format(length=len(privilege_list), name=name, key=key)
197            )
198            privilege_dict[key] = (privilege_list, name)
199
200        for mapping in json_file["Mappings"]:
201            entity = mapping["Entity"]
202            registry.write("// {}\n".format(entity))
203            for operation, privilege_list in mapping["OperationMap"].items():
204                privilege_string = get_privilege_string_from_list(
205                    privilege_list)
206                operation = operation.lower()
207
208                registry.write(
209                    "const static auto& {}{} = privilegeSet{};\n".format(
210                        operation,
211                        entity,
212                        privilege_dict[privilege_string][1]))
213            registry.write("\n")
214        registry.write(
215            "} // namespace redfish::privileges\n"
216            "// clang-format on\n")
217
218
219make_privilege_registry()
220