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