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