1#!/usr/bin/env python3
2import json
3import os
4
5import requests
6
7PRAGMA_ONCE = '''#pragma once
8'''
9
10WARNING = '''/****************************************************************
11 *                 READ THIS WARNING FIRST
12 * This is an auto-generated header which contains definitions
13 * for Redfish DMTF defined messages.
14 * DO NOT modify this registry outside of running the
15 * parse_registries.py script.  The definitions contained within
16 * this file are owned by DMTF.  Any modifications to these files
17 * should be first pushed to the relevant registry in the DMTF
18 * github organization.
19 ***************************************************************/'''
20
21REGISTRY_HEADER = PRAGMA_ONCE + WARNING + '''
22#include "registries.hpp"
23
24#include <array>
25
26// clang-format off
27
28namespace redfish::registries::{}
29{{
30'''
31
32SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__))
33
34include_path = os.path.realpath(
35    os.path.join(
36        SCRIPT_DIR,
37        "..",
38        "redfish-core",
39        "include",
40        "registries"))
41
42proxies = {
43    'https': os.environ.get("https_proxy", None)
44}
45
46
47def make_getter(dmtf_name, header_name, type_name):
48    url = 'https://redfish.dmtf.org/registries/{}'.format(dmtf_name)
49    dmtf = requests.get(url, proxies=proxies)
50    dmtf.raise_for_status()
51    json_file = json.loads(dmtf.text)
52    path = os.path.join(include_path, header_name)
53    return (path, json_file, type_name, url)
54
55
56files = []
57files.append(make_getter('Base.1.13.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(
78            "const Header header = {{\n"
79            "    \"{json_dict[@Redfish.Copyright]}\",\n"
80            "    \"{json_dict[@odata.type]}\",\n"
81            "    \"{json_dict[Id]}\",\n"
82            "    \"{json_dict[Name]}\",\n"
83            "    \"{json_dict[Language]}\",\n"
84            "    \"{json_dict[Description]}\",\n"
85            "    \"{json_dict[RegistryPrefix]}\",\n"
86            "    \"{json_dict[RegistryVersion]}\",\n"
87            "    \"{json_dict[OwningEntity]}\",\n"
88            "}};\n"
89            "constexpr const char* url =\n"
90            "    \"{url}\";\n"
91            "\n"
92            "constexpr std::array registry =\n"
93            "{{\n".format(
94                json_dict=json_dict,
95                url=url,
96            ))
97
98        messages_sorted = sorted(json_dict["Messages"].items())
99        for messageId, message in messages_sorted:
100            registry.write(
101                "    MessageEntry{{\n"
102                "        \"{messageId}\",\n"
103                "        {{\n"
104                "            \"{message[Description]}\",\n"
105                "            \"{message[Message]}\",\n"
106                "            \"{message[MessageSeverity]}\",\n"
107                "            {message[NumberOfArgs]},\n"
108                "            {{".format(
109                    messageId=messageId,
110                    message=message
111                ))
112            paramTypes = message.get("ParamTypes")
113            if paramTypes:
114                for paramType in paramTypes:
115                    registry.write(
116                        "\n"
117                        "                \"{}\",".format(paramType)
118                    )
119                registry.write("\n            },\n")
120            else:
121                registry.write("},\n")
122            registry.write(
123                "            \"{message[Resolution]}\",\n"
124                "        }}}},\n".format(message=message))
125
126        registry.write(
127            "\n};\n"
128            "\n"
129            "enum class Index\n"
130            "{\n"
131        )
132        for index, (messageId, message) in enumerate(messages_sorted):
133            messageId = messageId[0].lower() + messageId[1:]
134            registry.write(
135                "    {} = {},\n".format(messageId, index))
136        registry.write(
137            "}};\n"
138            "}} // namespace redfish::registries::{}\n"
139            .format(namespace))
140
141
142def get_privilege_string_from_list(privilege_list):
143    privilege_string = "{{\n"
144    for privilege_json in privilege_list:
145        privileges = privilege_json["Privilege"]
146        privilege_string += "    {"
147        for privilege in privileges:
148            if privilege == "NoAuth":
149                continue
150            privilege_string += "\""
151            privilege_string += privilege
152            privilege_string += "\",\n"
153        if privilege != "NoAuth":
154            privilege_string = privilege_string[:-2]
155        privilege_string += "}"
156        privilege_string += ",\n"
157    privilege_string = privilege_string[:-2]
158    privilege_string += "\n}}"
159    return privilege_string
160
161
162def get_variable_name_for_privilege_set(privilege_list):
163    names = []
164    for privilege_json in privilege_list:
165        privileges = privilege_json["Privilege"]
166        names.append("And".join(privileges))
167    return "Or".join(names)
168
169
170PRIVILEGE_HEADER = PRAGMA_ONCE + WARNING + '''
171#include "privileges.hpp"
172
173#include <array>
174
175// clang-format off
176
177namespace redfish::privileges
178{
179'''
180
181
182def make_privilege_registry():
183    path, json_file, type_name, url = \
184        make_getter('Redfish_1.3.0_PrivilegeRegistry.json',
185                    'privilege_registry.hpp', 'privilege')
186    with open(path, 'w') as registry:
187        registry.write(PRIVILEGE_HEADER)
188
189        privilege_dict = {}
190        for mapping in json_file["Mappings"]:
191            # first pass, identify all the unique privilege sets
192            for operation, privilege_list in mapping["OperationMap"].items():
193                privilege_dict[get_privilege_string_from_list(
194                    privilege_list)] = (privilege_list, )
195        for index, key in enumerate(privilege_dict):
196            (privilege_list, ) = privilege_dict[key]
197            name = get_variable_name_for_privilege_set(privilege_list)
198            registry.write(
199                "const std::array<Privileges, {length}> "
200                "privilegeSet{name} = {key};\n"
201                .format(length=len(privilege_list), name=name, key=key)
202            )
203            privilege_dict[key] = (privilege_list, name)
204
205        for mapping in json_file["Mappings"]:
206            entity = mapping["Entity"]
207            registry.write("// {}\n".format(entity))
208            for operation, privilege_list in mapping["OperationMap"].items():
209                privilege_string = get_privilege_string_from_list(
210                    privilege_list)
211                operation = operation.lower()
212
213                registry.write(
214                    "const static auto& {}{} = privilegeSet{};\n".format(
215                        operation,
216                        entity,
217                        privilege_dict[privilege_string][1]))
218            registry.write("\n")
219        registry.write(
220            "} // namespace redfish::privileges\n"
221            "// clang-format on\n")
222
223
224make_privilege_registry()
225