blob: e172923ed3377cd0da5d058d4a7fc99e7f742b1c [file] [log] [blame]
Nan Zhou313c1b72022-03-25 11:47:55 -07001#!/usr/bin/env python3
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -06002import argparse
Jason M. Bills70304cb2019-03-27 12:03:59 -07003import json
Nan Zhou6eaf0bd2022-08-07 01:18:45 +00004import os
Ed Tanous42079ec2024-11-16 13:32:29 -08005from collections import OrderedDict
Jason M. Bills70304cb2019-03-27 12:03:59 -07006
Nan Zhou6eaf0bd2022-08-07 01:18:45 +00007import requests
Jason M. Bills70304cb2019-03-27 12:03:59 -07008
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -06009PRAGMA_ONCE = """#pragma once
10"""
Nan Zhou043bec02022-09-20 18:12:13 +000011
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -060012WARNING = """/****************************************************************
Ed Tanous1cf53df2022-02-17 09:09:25 -080013 * READ THIS WARNING FIRST
Jason M. Bills70304cb2019-03-27 12:03:59 -070014 * This is an auto-generated header which contains definitions
15 * for Redfish DMTF defined messages.
Ed Tanous1cf53df2022-02-17 09:09:25 -080016 * DO NOT modify this registry outside of running the
Jason M. Bills0e2d0692022-04-01 13:59:05 -070017 * parse_registries.py script. The definitions contained within
Ed Tanous1cf53df2022-02-17 09:09:25 -080018 * this file are owned by DMTF. Any modifications to these files
19 * should be first pushed to the relevant registry in the DMTF
20 * github organization.
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -060021 ***************************************************************/"""
Ed Tanous1cf53df2022-02-17 09:09:25 -080022
Ed Tanous40e9b922024-09-10 13:50:16 -070023COPYRIGHT = """// SPDX-License-Identifier: Apache-2.0
24// SPDX-FileCopyrightText: Copyright OpenBMC Authors
25"""
26
27INCLUDES = """
Nan Zhou01c78a02022-09-20 18:17:20 +000028#include "registries.hpp"
29
30#include <array>
Jason M. Bills70304cb2019-03-27 12:03:59 -070031
Ed Tanous4d99bbb2022-02-17 10:02:57 -080032// clang-format off
33
Ed Tanousfffb8c12022-02-07 23:53:03 -080034namespace redfish::registries::{}
Jason M. Bills70304cb2019-03-27 12:03:59 -070035{{
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -060036"""
Ed Tanous40e9b922024-09-10 13:50:16 -070037
38REGISTRY_HEADER = f"{COPYRIGHT}{PRAGMA_ONCE}{WARNING}{INCLUDES}"
Jason M. Bills70304cb2019-03-27 12:03:59 -070039
40SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__))
41
Jason M. Billsac706372020-02-18 11:36:47 -080042include_path = os.path.realpath(
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -060043 os.path.join(SCRIPT_DIR, "..", "redfish-core", "include", "registries")
44)
Jason M. Bills70304cb2019-03-27 12:03:59 -070045
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -060046proxies = {"https": os.environ.get("https_proxy", None)}
Jason M. Bills70304cb2019-03-27 12:03:59 -070047
Jason M. Bills70304cb2019-03-27 12:03:59 -070048
James Feiste51c7102020-03-17 10:38:18 -070049def make_getter(dmtf_name, header_name, type_name):
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -060050 url = "https://redfish.dmtf.org/registries/{}".format(dmtf_name)
James Feiste51c7102020-03-17 10:38:18 -070051 dmtf = requests.get(url, proxies=proxies)
52 dmtf.raise_for_status()
Ed Tanous42079ec2024-11-16 13:32:29 -080053 json_file = json.loads(dmtf.text, object_pairs_hook=OrderedDict)
James Feiste51c7102020-03-17 10:38:18 -070054 path = os.path.join(include_path, header_name)
55 return (path, json_file, type_name, url)
56
57
Ed Tanous3e5faba2023-08-16 15:11:29 -070058def openbmc_local_getter():
Milton D. Miller II770362f2024-12-17 05:28:27 +000059 url = "https://raw.githubusercontent.com/openbmc/bmcweb/refs/heads/master/redfish-core/include/registries/openbmc.json"
Ed Tanous3e5faba2023-08-16 15:11:29 -070060 with open(
61 os.path.join(
62 SCRIPT_DIR,
63 "..",
64 "redfish-core",
65 "include",
66 "registries",
67 "openbmc.json",
68 ),
69 "rb",
70 ) as json_file:
71 json_file = json.load(json_file)
72
73 path = os.path.join(include_path, "openbmc_message_registry.hpp")
74 return (path, json_file, "openbmc", url)
75
76
Nan Zhou49aa131f2022-09-20 18:41:37 +000077def update_registries(files):
78 # Remove the old files
79 for file, json_dict, namespace, url in files:
80 try:
81 os.remove(file)
82 except BaseException:
83 print("{} not found".format(file))
Jason M. Bills70304cb2019-03-27 12:03:59 -070084
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -060085 with open(file, "w") as registry:
Ed Tanous56b81992024-12-02 10:36:37 -080086
87 version_split = json_dict["RegistryVersion"].split(".")
88
Nan Zhou49aa131f2022-09-20 18:41:37 +000089 registry.write(REGISTRY_HEADER.format(namespace))
90 # Parse the Registry header info
Ed Tanous5b9ef702022-02-17 12:19:32 -080091 registry.write(
Nan Zhou49aa131f2022-09-20 18:41:37 +000092 "const Header header = {{\n"
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -060093 ' "{json_dict[@Redfish.Copyright]}",\n'
94 ' "{json_dict[@odata.type]}",\n'
Ed Tanous56b81992024-12-02 10:36:37 -080095 " {version_split[0]},\n"
96 " {version_split[1]},\n"
97 " {version_split[2]},\n"
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -060098 ' "{json_dict[Name]}",\n'
99 ' "{json_dict[Language]}",\n'
100 ' "{json_dict[Description]}",\n'
101 ' "{json_dict[RegistryPrefix]}",\n'
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600102 ' "{json_dict[OwningEntity]}",\n'
Nan Zhou49aa131f2022-09-20 18:41:37 +0000103 "}};\n"
104 "constexpr const char* url =\n"
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600105 ' "{url}";\n'
Nan Zhou49aa131f2022-09-20 18:41:37 +0000106 "\n"
107 "constexpr std::array registry =\n"
108 "{{\n".format(
109 json_dict=json_dict,
110 url=url,
Ed Tanous56b81992024-12-02 10:36:37 -0800111 version_split=version_split,
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600112 )
113 )
Ed Tanous30a3c432022-02-07 09:37:21 -0800114
Nan Zhou49aa131f2022-09-20 18:41:37 +0000115 messages_sorted = sorted(json_dict["Messages"].items())
116 for messageId, message in messages_sorted:
117 registry.write(
118 " MessageEntry{{\n"
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600119 ' "{messageId}",\n'
Nan Zhou49aa131f2022-09-20 18:41:37 +0000120 " {{\n"
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600121 ' "{message[Description]}",\n'
122 ' "{message[Message]}",\n'
123 ' "{message[MessageSeverity]}",\n'
Nan Zhou49aa131f2022-09-20 18:41:37 +0000124 " {message[NumberOfArgs]},\n"
125 " {{".format(
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600126 messageId=messageId, message=message
127 )
128 )
Nan Zhou49aa131f2022-09-20 18:41:37 +0000129 paramTypes = message.get("ParamTypes")
130 if paramTypes:
131 for paramType in paramTypes:
132 registry.write(
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600133 '\n "{}",'.format(paramType)
Nan Zhou49aa131f2022-09-20 18:41:37 +0000134 )
135 registry.write("\n },\n")
136 else:
137 registry.write("},\n")
138 registry.write(
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600139 ' "{message[Resolution]}",\n'
140 " }}}},\n".format(message=message)
141 )
Nan Zhou49aa131f2022-09-20 18:41:37 +0000142
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600143 registry.write("\n};\n\nenum class Index\n{\n")
Nan Zhou49aa131f2022-09-20 18:41:37 +0000144 for index, (messageId, message) in enumerate(messages_sorted):
145 messageId = messageId[0].lower() + messageId[1:]
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600146 registry.write(" {} = {},\n".format(messageId, index))
Nan Zhou49aa131f2022-09-20 18:41:37 +0000147 registry.write(
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600148 "}};\n}} // namespace redfish::registries::{}\n".format(
149 namespace
150 )
151 )
Ed Tanoused398212021-06-09 17:05:54 -0700152
153
154def get_privilege_string_from_list(privilege_list):
155 privilege_string = "{{\n"
156 for privilege_json in privilege_list:
157 privileges = privilege_json["Privilege"]
158 privilege_string += " {"
159 for privilege in privileges:
160 if privilege == "NoAuth":
161 continue
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600162 privilege_string += '"'
Ed Tanoused398212021-06-09 17:05:54 -0700163 privilege_string += privilege
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600164 privilege_string += '",\n'
Ed Tanoused398212021-06-09 17:05:54 -0700165 if privilege != "NoAuth":
166 privilege_string = privilege_string[:-2]
167 privilege_string += "}"
168 privilege_string += ",\n"
169 privilege_string = privilege_string[:-2]
170 privilege_string += "\n}}"
171 return privilege_string
172
Ed Tanousf395daa2021-08-02 08:56:24 -0700173
Ed Tanoused398212021-06-09 17:05:54 -0700174def get_variable_name_for_privilege_set(privilege_list):
175 names = []
176 for privilege_json in privilege_list:
177 privileges = privilege_json["Privilege"]
178 names.append("And".join(privileges))
179 return "Or".join(names)
180
Ed Tanousf395daa2021-08-02 08:56:24 -0700181
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600182PRIVILEGE_HEADER = (
Ed Tanous40e9b922024-09-10 13:50:16 -0700183 COPYRIGHT
184 + PRAGMA_ONCE
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600185 + WARNING
186 + """
Nan Zhou01c78a02022-09-20 18:17:20 +0000187#include "privileges.hpp"
188
189#include <array>
Nan Zhou043bec02022-09-20 18:12:13 +0000190
191// clang-format off
192
193namespace redfish::privileges
194{
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600195"""
196)
Nan Zhou043bec02022-09-20 18:12:13 +0000197
198
Ed Tanous7ccfe682024-11-16 14:36:16 -0800199def get_response_code(entry_id, entry):
200 codes = {
201 "InternalError": "internal_server_error",
202 "OperationTimeout": "internal_server_error",
203 "PropertyValueResourceConflict": "conflict",
204 "ResourceInUse": "service_unavailable",
205 "ServiceTemporarilyUnavailable": "service_unavailable",
206 "ResourceCannotBeDeleted": "method_not_allowed",
207 "PropertyValueModified": "ok",
208 "InsufficientPrivilege": "forbidden",
209 "AccountForSessionNoLongerExists": "forbidden",
210 "ServiceDisabled": "service_unavailable",
211 "ServiceInUnknownState": "service_unavailable",
212 "EventSubscriptionLimitExceeded": "service_unavailable",
213 "ResourceAtUriUnauthorized": "unauthorized",
214 "SessionTerminated": "ok",
215 "SubscriptionTerminated": "ok",
216 "PropertyNotWritable": "forbidden",
217 "MaximumErrorsExceeded": "internal_server_error",
218 "GeneralError": "internal_server_error",
219 "PreconditionFailed": "precondition_failed",
220 "OperationFailed": "bad_gateway",
221 "ServiceShuttingDown": "service_unavailable",
222 "AccountRemoved": "ok",
223 "PropertyValueExternalConflict": "conflict",
224 "InsufficientStorage": "insufficient_storage",
225 "OperationNotAllowed": "method_not_allowed",
226 "ResourceNotFound": "not_found",
227 "CouldNotEstablishConnection": "not_found",
228 "AccessDenied": "forbidden",
229 "Success": None,
230 "Created": "created",
231 "NoValidSession": "forbidden",
232 "SessionLimitExceeded": "service_unavailable",
233 "ResourceExhaustion": "service_unavailable",
234 "AccountModified": "ok",
235 "PasswordChangeRequired": None,
236 "ResourceInStandby": "service_unavailable",
237 "GenerateSecretKeyRequired": "forbidden",
238 }
239
240 code = codes.get(entry_id, "NOCODE")
241 if code != "NOCODE":
242 return code
243
244 return "bad_request"
245
246
Ed Tanousf175c282024-12-02 15:12:50 -0800247def make_error_function(
248 entry_id, entry, is_header, registry_name, namespace_name
249):
Ed Tanous644cdcb2024-11-17 11:12:41 -0800250 arg_nonstring_types = {
251 "const boost::urls::url_view_base&": {
252 "AccessDenied": [1],
253 "CouldNotEstablishConnection": [1],
254 "GenerateSecretKeyRequired": [1],
255 "InvalidObject": [1],
256 "PasswordChangeRequired": [1],
257 "PropertyValueResourceConflict": [3],
258 "ResetRequired": [1],
259 "ResourceAtUriInUnknownFormat": [1],
260 "ResourceAtUriUnauthorized": [1],
261 "ResourceCreationConflict": [1],
262 "ResourceMissingAtURI": [1],
263 "SourceDoesNotSupportProtocol": [1],
264 },
265 "const nlohmann::json&": {
266 "ActionParameterValueError": [1],
267 "ActionParameterValueFormatError": [1],
268 "ActionParameterValueTypeError": [1],
269 "PropertyValueExternalConflict": [2],
270 "PropertyValueFormatError": [1],
271 "PropertyValueIncorrect": [2],
272 "PropertyValueModified": [2],
273 "PropertyValueNotInList": [1],
274 "PropertyValueOutOfRange": [1],
275 "PropertyValueResourceConflict": [2],
276 "PropertyValueTypeError": [1],
277 "QueryParameterValueFormatError": [1],
278 "QueryParameterValueTypeError": [1],
279 },
280 "uint64_t": {
281 "ArraySizeTooLong": [2],
282 "InvalidIndex": [1],
283 "StringValueTooLong": [2],
Ed Tanousf175c282024-12-02 15:12:50 -0800284 "TaskProgressChanged": [2],
Ed Tanous644cdcb2024-11-17 11:12:41 -0800285 },
Ed Tanous42079ec2024-11-16 13:32:29 -0800286 }
287
Ed Tanous7ccfe682024-11-16 14:36:16 -0800288 out = ""
289 args = []
290 argtypes = []
291 for arg_index, arg in enumerate(entry.get("ParamTypes", [])):
292 arg_index += 1
Ed Tanous644cdcb2024-11-17 11:12:41 -0800293 typename = "std::string_view"
294 for typestring, entries in arg_nonstring_types.items():
295 if arg_index in entries.get(entry_id, []):
296 typename = typestring
297
Ed Tanous7ccfe682024-11-16 14:36:16 -0800298 argtypes.append(typename)
299 args.append(f"{typename} arg{arg_index}")
300 function_name = entry_id[0].lower() + entry_id[1:]
301 arg = ", ".join(args)
302 out += f"nlohmann::json {function_name}({arg})"
303
304 if is_header:
305 out += ";\n\n"
306 else:
307 out += "\n{\n"
308 to_array_type = ""
309 if argtypes:
310 outargs = []
311 for index, typename in enumerate(argtypes):
312 index += 1
313 if typename == "const nlohmann::json&":
314 out += f"std::string arg{index}Str = arg{index}.dump(-1, ' ', true, nlohmann::json::error_handler_t::replace);\n"
Ed Tanous644cdcb2024-11-17 11:12:41 -0800315 elif typename == "uint64_t":
Ed Tanous7ccfe682024-11-16 14:36:16 -0800316 out += f"std::string arg{index}Str = std::to_string(arg{index});\n"
317
318 for index, typename in enumerate(argtypes):
319 index += 1
320 if typename == "const boost::urls::url_view_base&":
321 outargs.append(f"arg{index}.buffer()")
322 to_array_type = "<std::string_view>"
323 elif typename == "const nlohmann::json&":
324 outargs.append(f"arg{index}Str")
325 to_array_type = "<std::string_view>"
Ed Tanous644cdcb2024-11-17 11:12:41 -0800326 elif typename == "uint64_t":
Ed Tanous7ccfe682024-11-16 14:36:16 -0800327 outargs.append(f"arg{index}Str")
328 to_array_type = "<std::string_view>"
329 else:
330 outargs.append(f"arg{index}")
331 argstring = ", ".join(outargs)
Ed Tanous7ccfe682024-11-16 14:36:16 -0800332
333 if argtypes:
334 arg_param = f"std::to_array{to_array_type}({{{argstring}}})"
335 else:
336 arg_param = "{}"
Ed Tanousf175c282024-12-02 15:12:50 -0800337 out += f" return getLog(redfish::registries::{namespace_name}::Index::{function_name}, {arg_param});"
Ed Tanous7ccfe682024-11-16 14:36:16 -0800338 out += "\n}\n\n"
Ed Tanousf175c282024-12-02 15:12:50 -0800339 if registry_name == "Base":
340 args.insert(0, "crow::Response& res")
Ed Tanous7ccfe682024-11-16 14:36:16 -0800341 if entry_id == "InternalError":
Ed Tanousf175c282024-12-02 15:12:50 -0800342 if is_header:
343 args.append(
344 "std::source_location location = std::source_location::current()"
345 )
346 else:
347 args.append("const std::source_location location")
348 arg = ", ".join(args)
349 out += f"void {function_name}({arg})"
350 if is_header:
351 out += ";\n"
Ed Tanous7ccfe682024-11-16 14:36:16 -0800352 else:
Ed Tanousf175c282024-12-02 15:12:50 -0800353 out += "\n{\n"
354 if entry_id == "InternalError":
355 out += """BMCWEB_LOG_CRITICAL("Internal Error {}({}:{}) `{}`: ", location.file_name(),
356 location.line(), location.column(),
357 location.function_name());\n"""
358
359 if entry_id == "ServiceTemporarilyUnavailable":
360 out += "res.addHeader(boost::beast::http::field::retry_after, arg1);"
361
362 res = get_response_code(entry_id, entry)
363 if res:
364 out += f" res.result(boost::beast::http::status::{res});\n"
365 args_out = ", ".join([f"arg{x+1}" for x in range(len(argtypes))])
366
367 addMessageToJson = {
368 "PropertyDuplicate": 1,
369 "ResourceAlreadyExists": 2,
370 "CreateFailedMissingReqProperties": 1,
371 "PropertyValueFormatError": 2,
372 "PropertyValueNotInList": 2,
373 "PropertyValueTypeError": 2,
374 "PropertyValueError": 1,
375 "PropertyNotWritable": 1,
376 "PropertyValueModified": 1,
377 "PropertyMissing": 1,
378 }
379
380 addMessageToRoot = [
381 "SessionTerminated",
382 "SubscriptionTerminated",
383 "AccountRemoved",
384 "Created",
385 "Success",
386 "PasswordChangeRequired",
387 ]
388
389 if entry_id in addMessageToJson:
390 out += f" addMessageToJson(res.jsonValue, {function_name}({args_out}), arg{addMessageToJson[entry_id]});\n"
391 elif entry_id in addMessageToRoot:
392 out += f" addMessageToJsonRoot(res.jsonValue, {function_name}({args_out}));\n"
393 else:
394 out += f" addMessageToErrorJson(res.jsonValue, {function_name}({args_out}));\n"
395 out += "}\n"
Ed Tanous7ccfe682024-11-16 14:36:16 -0800396 out += "\n"
397 return out
398
399
Ed Tanousf175c282024-12-02 15:12:50 -0800400def create_error_registry(
401 entry, registry_version, registry_name, namespace_name, filename
402):
Ed Tanous42079ec2024-11-16 13:32:29 -0800403 file, json_dict, namespace, url = entry
Ed Tanousf175c282024-12-02 15:12:50 -0800404 base_filename = filename + "_messages"
Ed Tanous42079ec2024-11-16 13:32:29 -0800405
Ed Tanous42079ec2024-11-16 13:32:29 -0800406 error_messages_hpp = os.path.join(
Ed Tanousf175c282024-12-02 15:12:50 -0800407 SCRIPT_DIR, "..", "redfish-core", "include", f"{base_filename}.hpp"
Ed Tanous42079ec2024-11-16 13:32:29 -0800408 )
Ed Tanousf8cca872024-11-16 22:47:34 -0800409 messages = json_dict["Messages"]
410
Ed Tanous42079ec2024-11-16 13:32:29 -0800411 with open(
412 error_messages_hpp,
413 "w",
414 ) as out:
415 out.write(PRAGMA_ONCE)
416 out.write(WARNING)
417 out.write(
418 """
419
420#include "http_response.hpp"
421
422#include <boost/url/url_view_base.hpp>
423#include <nlohmann/json.hpp>
424
Ed Tanous42079ec2024-11-16 13:32:29 -0800425#include <source_location>
Ed Tanous42079ec2024-11-16 13:32:29 -0800426#include <string_view>
427
428// IWYU pragma: no_forward_declare crow::Response
429
430namespace redfish
431{
432
433namespace messages
434{
Ed Tanous42079ec2024-11-16 13:32:29 -0800435"""
436 )
Ed Tanousf175c282024-12-02 15:12:50 -0800437 if registry_name == "Base":
438 out.write(
439 f'constexpr const char* messageVersionPrefix = "{registry_name}.{registry_version}.";'
440 )
441 out.write(
442 """
443 constexpr const char* messageAnnotation = "@Message.ExtendedInfo";
Ed Tanous42079ec2024-11-16 13:32:29 -0800444
Ed Tanousf175c282024-12-02 15:12:50 -0800445 /**
446 * @brief Moves all error messages from the |source| JSON to |target|
447 */
448 void moveErrorsToErrorJson(nlohmann::json& target, nlohmann::json& source);
Ed Tanous352945b2024-11-17 22:45:51 -0800449
Ed Tanousf175c282024-12-02 15:12:50 -0800450 """
451 )
Ed Tanous42079ec2024-11-16 13:32:29 -0800452 for entry_id, entry in messages.items():
453 message = entry["Message"]
454 for index in range(1, 10):
455 message = message.replace(f"'%{index}'", f"<arg{index}>")
456 message = message.replace(f"%{index}", f"<arg{index}>")
457
Ed Tanousf175c282024-12-02 15:12:50 -0800458 if registry_name == "Base":
459 out.write("/**\n")
460 out.write(f"* @brief Formats {entry_id} message into JSON\n")
461 out.write(f'* Message body: "{message}"\n')
462 out.write("*\n")
463 arg_index = 0
464 for arg_index, arg in enumerate(entry.get("ParamTypes", [])):
465 arg_index += 1
Ed Tanous42079ec2024-11-16 13:32:29 -0800466
Ed Tanousf175c282024-12-02 15:12:50 -0800467 out.write(
468 f"* @param[in] arg{arg_index} Parameter of message that will replace %{arg_index} in its body.\n"
469 )
470 out.write("*\n")
Ed Tanous42079ec2024-11-16 13:32:29 -0800471 out.write(
Ed Tanousf175c282024-12-02 15:12:50 -0800472 f"* @returns Message {entry_id} formatted to JSON */\n"
Ed Tanous42079ec2024-11-16 13:32:29 -0800473 )
Ed Tanous42079ec2024-11-16 13:32:29 -0800474
Ed Tanousf175c282024-12-02 15:12:50 -0800475 out.write(
476 make_error_function(
477 entry_id, entry, True, registry_name, namespace_name
478 )
479 )
Ed Tanous42079ec2024-11-16 13:32:29 -0800480 out.write(" }\n")
481 out.write("}\n")
Ed Tanous7ccfe682024-11-16 14:36:16 -0800482
483 error_messages_cpp = os.path.join(
Ed Tanousf175c282024-12-02 15:12:50 -0800484 SCRIPT_DIR, "..", "redfish-core", "src", f"{base_filename}.cpp"
Ed Tanous7ccfe682024-11-16 14:36:16 -0800485 )
486 with open(
487 error_messages_cpp,
488 "w",
489 ) as out:
490 out.write(WARNING)
Ed Tanousf175c282024-12-02 15:12:50 -0800491 out.write(f'\n#include "{base_filename}.hpp"\n')
Ed Tanous847deee2024-12-02 15:28:10 -0800492 headers = []
Ed Tanous7ccfe682024-11-16 14:36:16 -0800493
Ed Tanous847deee2024-12-02 15:28:10 -0800494 headers.append('"registries.hpp"')
Ed Tanousf175c282024-12-02 15:12:50 -0800495 if registry_name == "Base":
496 reg_name_lower = "base"
Ed Tanous847deee2024-12-02 15:28:10 -0800497 headers.append('"http_response.hpp"')
498 headers.append('"logging.hpp"')
499 headers.append("<boost/beast/http/field.hpp>")
500 headers.append("<boost/beast/http/status.hpp>")
501 headers.append("<boost/url/url_view_base.hpp>")
502 headers.append("<source_location>")
Ed Tanousf175c282024-12-02 15:12:50 -0800503 else:
504 reg_name_lower = namespace_name.lower()
Ed Tanous847deee2024-12-02 15:28:10 -0800505 headers.append(f'"registries/{reg_name_lower}_message_registry.hpp"')
Ed Tanous7ccfe682024-11-16 14:36:16 -0800506
Ed Tanous847deee2024-12-02 15:28:10 -0800507 headers.append("<nlohmann/json.hpp>")
508 headers.append("<array>")
509 headers.append("<cstddef>")
510 headers.append("<span>")
511
Ed Tanousa8a5bc12024-12-02 15:43:16 -0800512 if registry_name not in ("ResourceEvent", "HeartbeatEvent"):
Ed Tanous847deee2024-12-02 15:28:10 -0800513 headers.append("<cstdint>")
514 headers.append("<string>")
515 headers.append("<string_view>")
516
517 for header in headers:
518 out.write(f"#include {header}\n")
519
Ed Tanousf175c282024-12-02 15:12:50 -0800520 out.write(
521 """
Ed Tanous7ccfe682024-11-16 14:36:16 -0800522// Clang can't seem to decide whether this header needs to be included or not,
523// and is inconsistent. Include it for now
524// NOLINTNEXTLINE(misc-include-cleaner)
525#include <utility>
526
527namespace redfish
528{
529
530namespace messages
531{
Ed Tanousf175c282024-12-02 15:12:50 -0800532"""
533 )
Ed Tanous7ccfe682024-11-16 14:36:16 -0800534
Ed Tanousf175c282024-12-02 15:12:50 -0800535 if registry_name == "Base":
536 out.write(
537 """
Ed Tanous7ccfe682024-11-16 14:36:16 -0800538static void addMessageToErrorJson(nlohmann::json& target,
539 const nlohmann::json& message)
540{
541 auto& error = target["error"];
542
543 // If this is the first error message, fill in the information from the
544 // first error message to the top level struct
545 if (!error.is_object())
546 {
547 auto messageIdIterator = message.find("MessageId");
548 if (messageIdIterator == message.end())
549 {
550 BMCWEB_LOG_CRITICAL(
551 "Attempt to add error message without MessageId");
552 return;
553 }
554
555 auto messageFieldIterator = message.find("Message");
556 if (messageFieldIterator == message.end())
557 {
558 BMCWEB_LOG_CRITICAL("Attempt to add error message without Message");
559 return;
560 }
561 error["code"] = *messageIdIterator;
562 error["message"] = *messageFieldIterator;
563 }
564 else
565 {
566 // More than 1 error occurred, so the message has to be generic
567 error["code"] = std::string(messageVersionPrefix) + "GeneralError";
568 error["message"] = "A general error has occurred. See Resolution for "
569 "information on how to resolve the error.";
570 }
571
572 // This check could technically be done in the default construction
573 // branch above, but because we need the pointer to the extended info field
574 // anyway, it's more efficient to do it here.
575 auto& extendedInfo = error[messages::messageAnnotation];
576 if (!extendedInfo.is_array())
577 {
578 extendedInfo = nlohmann::json::array();
579 }
580
581 extendedInfo.push_back(message);
582}
583
584void moveErrorsToErrorJson(nlohmann::json& target, nlohmann::json& source)
585{
586 if (!source.is_object())
587 {
588 return;
589 }
590 auto errorIt = source.find("error");
591 if (errorIt == source.end())
592 {
593 // caller puts error message in root
594 messages::addMessageToErrorJson(target, source);
595 source.clear();
596 return;
597 }
598 auto extendedInfoIt = errorIt->find(messages::messageAnnotation);
599 if (extendedInfoIt == errorIt->end())
600 {
601 return;
602 }
603 const nlohmann::json::array_t* extendedInfo =
604 (*extendedInfoIt).get_ptr<const nlohmann::json::array_t*>();
605 if (extendedInfo == nullptr)
606 {
607 source.erase(errorIt);
608 return;
609 }
610 for (const nlohmann::json& message : *extendedInfo)
611 {
612 addMessageToErrorJson(target, message);
613 }
614 source.erase(errorIt);
615}
616
617static void addMessageToJsonRoot(nlohmann::json& target,
618 const nlohmann::json& message)
619{
620 if (!target[messages::messageAnnotation].is_array())
621 {
622 // Force object to be an array
623 target[messages::messageAnnotation] = nlohmann::json::array();
624 }
625
626 target[messages::messageAnnotation].push_back(message);
627}
628
629static void addMessageToJson(nlohmann::json& target,
630 const nlohmann::json& message,
631 std::string_view fieldPath)
632{
633 std::string extendedInfo(fieldPath);
634 extendedInfo += messages::messageAnnotation;
635
636 nlohmann::json& field = target[extendedInfo];
637 if (!field.is_array())
638 {
639 // Force object to be an array
640 field = nlohmann::json::array();
641 }
642
643 // Object exists and it is an array so we can just push in the message
644 field.push_back(message);
645}
Ed Tanous7ccfe682024-11-16 14:36:16 -0800646"""
Ed Tanousf175c282024-12-02 15:12:50 -0800647 )
648 out.write(
649 """
650static nlohmann::json getLog(redfish::registries::{namespace_name}::Index name,
651 std::span<const std::string_view> args)
652{{
653 size_t index = static_cast<size_t>(name);
654 if (index >= redfish::registries::{namespace_name}::registry.size())
655 {{
656 return {{}};
657 }}
658 return getLogFromRegistry(redfish::registries::{namespace_name}::header,
659 redfish::registries::{namespace_name}::registry, index, args);
660}}
661
662""".format(
663 namespace_name=namespace_name
664 )
Ed Tanous7ccfe682024-11-16 14:36:16 -0800665 )
666 for entry_id, entry in messages.items():
667 out.write(
668 f"""/**
669 * @internal
670 * @brief Formats {entry_id} message into JSON
671 *
672 * See header file for more information
673 * @endinternal
674 */
675"""
676 )
677 message = entry["Message"]
Ed Tanousf175c282024-12-02 15:12:50 -0800678 out.write(
679 make_error_function(
680 entry_id, entry, False, registry_name, namespace_name
681 )
682 )
Ed Tanous7ccfe682024-11-16 14:36:16 -0800683
684 out.write(" }\n")
685 out.write("}\n")
686 os.system(f"clang-format -i {error_messages_hpp} {error_messages_cpp}")
Ed Tanous42079ec2024-11-16 13:32:29 -0800687
688
Ed Tanoused398212021-06-09 17:05:54 -0700689def make_privilege_registry():
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600690 path, json_file, type_name, url = make_getter(
Gunnar Mills5910d942024-04-16 12:07:17 -0500691 "Redfish_1.5.0_PrivilegeRegistry.json",
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600692 "privilege_registry.hpp",
693 "privilege",
694 )
695 with open(path, "w") as registry:
Nan Zhou043bec02022-09-20 18:12:13 +0000696 registry.write(PRIVILEGE_HEADER)
Ed Tanoused398212021-06-09 17:05:54 -0700697
698 privilege_dict = {}
699 for mapping in json_file["Mappings"]:
700 # first pass, identify all the unique privilege sets
701 for operation, privilege_list in mapping["OperationMap"].items():
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600702 privilege_dict[
703 get_privilege_string_from_list(privilege_list)
704 ] = (privilege_list,)
Ed Tanoused398212021-06-09 17:05:54 -0700705 for index, key in enumerate(privilege_dict):
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600706 (privilege_list,) = privilege_dict[key]
Ed Tanoused398212021-06-09 17:05:54 -0700707 name = get_variable_name_for_privilege_set(privilege_list)
Ed Tanousf395daa2021-08-02 08:56:24 -0700708 registry.write(
Ed Tanous5b9ef702022-02-17 12:19:32 -0800709 "const std::array<Privileges, {length}> "
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600710 "privilegeSet{name} = {key};\n".format(
711 length=len(privilege_list), name=name, key=key
712 )
Ed Tanous5b9ef702022-02-17 12:19:32 -0800713 )
Ed Tanoused398212021-06-09 17:05:54 -0700714 privilege_dict[key] = (privilege_list, name)
Ed Tanoused398212021-06-09 17:05:54 -0700715
716 for mapping in json_file["Mappings"]:
717 entity = mapping["Entity"]
Ed Tanous4d99bbb2022-02-17 10:02:57 -0800718 registry.write("// {}\n".format(entity))
Ed Tanoused398212021-06-09 17:05:54 -0700719 for operation, privilege_list in mapping["OperationMap"].items():
720 privilege_string = get_privilege_string_from_list(
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600721 privilege_list
722 )
Ed Tanoused398212021-06-09 17:05:54 -0700723 operation = operation.lower()
724
Ed Tanousf395daa2021-08-02 08:56:24 -0700725 registry.write(
726 "const static auto& {}{} = privilegeSet{};\n".format(
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600727 operation, entity, privilege_dict[privilege_string][1]
728 )
729 )
Ed Tanoused398212021-06-09 17:05:54 -0700730 registry.write("\n")
Ed Tanous5b9ef702022-02-17 12:19:32 -0800731 registry.write(
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600732 "} // namespace redfish::privileges\n// clang-format on\n"
733 )
Ed Tanoused398212021-06-09 17:05:54 -0700734
735
Gunnar Mills665e7602024-04-10 13:14:41 -0500736def to_pascal_case(text):
737 s = text.replace("_", " ")
738 s = s.split()
739 if len(text) == 0:
740 return text
741 return "".join(i.capitalize() for i in s[0:])
742
743
Nan Zhou49aa131f2022-09-20 18:41:37 +0000744def main():
Ed Tanousc8895b02025-01-03 11:44:08 -0800745 dmtf_registries = OrderedDict(
746 [
747 ("base", "1.19.0"),
748 ("composition", "1.1.2"),
749 ("environmental", "1.0.1"),
750 ("ethernet_fabric", "1.0.1"),
751 ("fabric", "1.0.2"),
752 ("heartbeat_event", "1.0.1"),
753 ("job_event", "1.0.1"),
754 ("license", "1.0.3"),
755 ("log_service", "1.0.1"),
756 ("network_device", "1.0.3"),
757 ("platform", "1.0.1"),
758 ("power", "1.0.1"),
759 ("resource_event", "1.3.0"),
760 ("sensor_event", "1.0.1"),
761 ("storage_device", "1.2.1"),
762 ("task_event", "1.0.3"),
763 ("telemetry", "1.0.0"),
764 ("update", "1.0.2"),
765 ]
766 )
Gunnar Mills665e7602024-04-10 13:14:41 -0500767
Nan Zhou49aa131f2022-09-20 18:41:37 +0000768 parser = argparse.ArgumentParser()
769 parser.add_argument(
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600770 "--registries",
771 type=str,
Gunnar Mills665e7602024-04-10 13:14:41 -0500772 default="privilege,openbmc,"
Tam Nguyen7e6d0322024-12-27 09:47:38 +0700773 + ",".join([dmtf for dmtf in dmtf_registries]),
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600774 help="Comma delimited list of registries to update",
775 )
Nan Zhou49aa131f2022-09-20 18:41:37 +0000776
777 args = parser.parse_args()
778
779 registries = set(args.registries.split(","))
780 files = []
Tam Nguyen7e6d0322024-12-27 09:47:38 +0700781 registries_map = OrderedDict()
Nan Zhou49aa131f2022-09-20 18:41:37 +0000782
Tam Nguyen7e6d0322024-12-27 09:47:38 +0700783 for registry, version in dmtf_registries.items():
Gunnar Mills665e7602024-04-10 13:14:41 -0500784 if registry in registries:
785 registry_pascal_case = to_pascal_case(registry)
786 files.append(
787 make_getter(
788 f"{registry_pascal_case}.{version}.json",
789 f"{registry}_message_registry.hpp",
790 registry,
791 )
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600792 )
Tam Nguyen7e6d0322024-12-27 09:47:38 +0700793 registries_map[registry] = files[-1]
Ed Tanous3e5faba2023-08-16 15:11:29 -0700794 if "openbmc" in registries:
795 files.append(openbmc_local_getter())
Nan Zhou49aa131f2022-09-20 18:41:37 +0000796
797 update_registries(files)
798
Tam Nguyen7e6d0322024-12-27 09:47:38 +0700799 if "base" in registries_map:
800 create_error_registry(
Ed Tanousc8895b02025-01-03 11:44:08 -0800801 registries_map["base"],
802 dmtf_registries["base"],
803 "Base",
804 "base",
805 "error",
Tam Nguyen7e6d0322024-12-27 09:47:38 +0700806 )
807 if "heartbeat_event" in registries_map:
808 create_error_registry(
809 registries_map["heartbeat_event"],
810 dmtf_registries["heartbeat_event"],
811 "HeartbeatEvent",
812 "heartbeat_event",
813 "heartbeat",
814 )
815 if "resource_event" in registries_map:
816 create_error_registry(
817 registries_map["resource_event"],
818 dmtf_registries["resource_event"],
819 "ResourceEvent",
820 "resource_event",
821 "resource",
822 )
823 if "task_event" in registries_map:
824 create_error_registry(
Ed Tanousc8895b02025-01-03 11:44:08 -0800825 registries_map["task_event"],
826 dmtf_registries["task_event"],
827 "TaskEvent",
828 "task_event",
829 "task",
Tam Nguyen7e6d0322024-12-27 09:47:38 +0700830 )
831
Nan Zhou49aa131f2022-09-20 18:41:37 +0000832 if "privilege" in registries:
833 make_privilege_registry()
834
835
836if __name__ == "__main__":
837 main()