blob: 20aac87def71557f35f78428b4f4d4d502116bad [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
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -060023REGISTRY_HEADER = (
24 PRAGMA_ONCE
25 + WARNING
26 + """
Nan Zhou01c78a02022-09-20 18:17:20 +000027#include "registries.hpp"
28
29#include <array>
Jason M. Bills70304cb2019-03-27 12:03:59 -070030
Ed Tanous4d99bbb2022-02-17 10:02:57 -080031// clang-format off
32
Ed Tanousfffb8c12022-02-07 23:53:03 -080033namespace redfish::registries::{}
Jason M. Bills70304cb2019-03-27 12:03:59 -070034{{
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -060035"""
36)
Jason M. Bills70304cb2019-03-27 12:03:59 -070037
38SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__))
39
Jason M. Billsac706372020-02-18 11:36:47 -080040include_path = os.path.realpath(
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -060041 os.path.join(SCRIPT_DIR, "..", "redfish-core", "include", "registries")
42)
Jason M. Bills70304cb2019-03-27 12:03:59 -070043
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -060044proxies = {"https": os.environ.get("https_proxy", None)}
Jason M. Bills70304cb2019-03-27 12:03:59 -070045
Jason M. Bills70304cb2019-03-27 12:03:59 -070046
James Feiste51c7102020-03-17 10:38:18 -070047def make_getter(dmtf_name, header_name, type_name):
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -060048 url = "https://redfish.dmtf.org/registries/{}".format(dmtf_name)
James Feiste51c7102020-03-17 10:38:18 -070049 dmtf = requests.get(url, proxies=proxies)
50 dmtf.raise_for_status()
Ed Tanous42079ec2024-11-16 13:32:29 -080051 json_file = json.loads(dmtf.text, object_pairs_hook=OrderedDict)
James Feiste51c7102020-03-17 10:38:18 -070052 path = os.path.join(include_path, header_name)
53 return (path, json_file, type_name, url)
54
55
Ed Tanous3e5faba2023-08-16 15:11:29 -070056def openbmc_local_getter():
Ed Tanous66aabb72024-12-10 16:34:14 -080057 url = "https://github.com/openbmc/bmcweb/blob/master/redfish-core/include/registries/openbmc.json"
Ed Tanous3e5faba2023-08-16 15:11:29 -070058 with open(
59 os.path.join(
60 SCRIPT_DIR,
61 "..",
62 "redfish-core",
63 "include",
64 "registries",
65 "openbmc.json",
66 ),
67 "rb",
68 ) as json_file:
69 json_file = json.load(json_file)
70
71 path = os.path.join(include_path, "openbmc_message_registry.hpp")
72 return (path, json_file, "openbmc", url)
73
74
Nan Zhou49aa131f2022-09-20 18:41:37 +000075def update_registries(files):
76 # Remove the old files
77 for file, json_dict, namespace, url in files:
78 try:
79 os.remove(file)
80 except BaseException:
81 print("{} not found".format(file))
Jason M. Bills70304cb2019-03-27 12:03:59 -070082
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -060083 with open(file, "w") as registry:
Ed Tanous56b81992024-12-02 10:36:37 -080084
85 version_split = json_dict["RegistryVersion"].split(".")
86
Nan Zhou49aa131f2022-09-20 18:41:37 +000087 registry.write(REGISTRY_HEADER.format(namespace))
88 # Parse the Registry header info
Ed Tanous5b9ef702022-02-17 12:19:32 -080089 registry.write(
Nan Zhou49aa131f2022-09-20 18:41:37 +000090 "const Header header = {{\n"
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -060091 ' "{json_dict[@Redfish.Copyright]}",\n'
92 ' "{json_dict[@odata.type]}",\n'
Ed Tanous56b81992024-12-02 10:36:37 -080093 " {version_split[0]},\n"
94 " {version_split[1]},\n"
95 " {version_split[2]},\n"
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -060096 ' "{json_dict[Name]}",\n'
97 ' "{json_dict[Language]}",\n'
98 ' "{json_dict[Description]}",\n'
99 ' "{json_dict[RegistryPrefix]}",\n'
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600100 ' "{json_dict[OwningEntity]}",\n'
Nan Zhou49aa131f2022-09-20 18:41:37 +0000101 "}};\n"
102 "constexpr const char* url =\n"
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600103 ' "{url}";\n'
Nan Zhou49aa131f2022-09-20 18:41:37 +0000104 "\n"
105 "constexpr std::array registry =\n"
106 "{{\n".format(
107 json_dict=json_dict,
108 url=url,
Ed Tanous56b81992024-12-02 10:36:37 -0800109 version_split=version_split,
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600110 )
111 )
Ed Tanous30a3c432022-02-07 09:37:21 -0800112
Nan Zhou49aa131f2022-09-20 18:41:37 +0000113 messages_sorted = sorted(json_dict["Messages"].items())
114 for messageId, message in messages_sorted:
115 registry.write(
116 " MessageEntry{{\n"
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600117 ' "{messageId}",\n'
Nan Zhou49aa131f2022-09-20 18:41:37 +0000118 " {{\n"
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600119 ' "{message[Description]}",\n'
120 ' "{message[Message]}",\n'
121 ' "{message[MessageSeverity]}",\n'
Nan Zhou49aa131f2022-09-20 18:41:37 +0000122 " {message[NumberOfArgs]},\n"
123 " {{".format(
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600124 messageId=messageId, message=message
125 )
126 )
Nan Zhou49aa131f2022-09-20 18:41:37 +0000127 paramTypes = message.get("ParamTypes")
128 if paramTypes:
129 for paramType in paramTypes:
130 registry.write(
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600131 '\n "{}",'.format(paramType)
Nan Zhou49aa131f2022-09-20 18:41:37 +0000132 )
133 registry.write("\n },\n")
134 else:
135 registry.write("},\n")
136 registry.write(
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600137 ' "{message[Resolution]}",\n'
138 " }}}},\n".format(message=message)
139 )
Nan Zhou49aa131f2022-09-20 18:41:37 +0000140
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600141 registry.write("\n};\n\nenum class Index\n{\n")
Nan Zhou49aa131f2022-09-20 18:41:37 +0000142 for index, (messageId, message) in enumerate(messages_sorted):
143 messageId = messageId[0].lower() + messageId[1:]
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600144 registry.write(" {} = {},\n".format(messageId, index))
Nan Zhou49aa131f2022-09-20 18:41:37 +0000145 registry.write(
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600146 "}};\n}} // namespace redfish::registries::{}\n".format(
147 namespace
148 )
149 )
Ed Tanoused398212021-06-09 17:05:54 -0700150
151
152def get_privilege_string_from_list(privilege_list):
153 privilege_string = "{{\n"
154 for privilege_json in privilege_list:
155 privileges = privilege_json["Privilege"]
156 privilege_string += " {"
157 for privilege in privileges:
158 if privilege == "NoAuth":
159 continue
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600160 privilege_string += '"'
Ed Tanoused398212021-06-09 17:05:54 -0700161 privilege_string += privilege
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600162 privilege_string += '",\n'
Ed Tanoused398212021-06-09 17:05:54 -0700163 if privilege != "NoAuth":
164 privilege_string = privilege_string[:-2]
165 privilege_string += "}"
166 privilege_string += ",\n"
167 privilege_string = privilege_string[:-2]
168 privilege_string += "\n}}"
169 return privilege_string
170
Ed Tanousf395daa2021-08-02 08:56:24 -0700171
Ed Tanoused398212021-06-09 17:05:54 -0700172def get_variable_name_for_privilege_set(privilege_list):
173 names = []
174 for privilege_json in privilege_list:
175 privileges = privilege_json["Privilege"]
176 names.append("And".join(privileges))
177 return "Or".join(names)
178
Ed Tanousf395daa2021-08-02 08:56:24 -0700179
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600180PRIVILEGE_HEADER = (
181 PRAGMA_ONCE
182 + WARNING
183 + """
Nan Zhou01c78a02022-09-20 18:17:20 +0000184#include "privileges.hpp"
185
186#include <array>
Nan Zhou043bec02022-09-20 18:12:13 +0000187
188// clang-format off
189
190namespace redfish::privileges
191{
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600192"""
193)
Nan Zhou043bec02022-09-20 18:12:13 +0000194
195
Ed Tanous7ccfe682024-11-16 14:36:16 -0800196def get_response_code(entry_id, entry):
197 codes = {
198 "InternalError": "internal_server_error",
199 "OperationTimeout": "internal_server_error",
200 "PropertyValueResourceConflict": "conflict",
201 "ResourceInUse": "service_unavailable",
202 "ServiceTemporarilyUnavailable": "service_unavailable",
203 "ResourceCannotBeDeleted": "method_not_allowed",
204 "PropertyValueModified": "ok",
205 "InsufficientPrivilege": "forbidden",
206 "AccountForSessionNoLongerExists": "forbidden",
207 "ServiceDisabled": "service_unavailable",
208 "ServiceInUnknownState": "service_unavailable",
209 "EventSubscriptionLimitExceeded": "service_unavailable",
210 "ResourceAtUriUnauthorized": "unauthorized",
211 "SessionTerminated": "ok",
212 "SubscriptionTerminated": "ok",
213 "PropertyNotWritable": "forbidden",
214 "MaximumErrorsExceeded": "internal_server_error",
215 "GeneralError": "internal_server_error",
216 "PreconditionFailed": "precondition_failed",
217 "OperationFailed": "bad_gateway",
218 "ServiceShuttingDown": "service_unavailable",
219 "AccountRemoved": "ok",
220 "PropertyValueExternalConflict": "conflict",
221 "InsufficientStorage": "insufficient_storage",
222 "OperationNotAllowed": "method_not_allowed",
223 "ResourceNotFound": "not_found",
224 "CouldNotEstablishConnection": "not_found",
225 "AccessDenied": "forbidden",
226 "Success": None,
227 "Created": "created",
228 "NoValidSession": "forbidden",
229 "SessionLimitExceeded": "service_unavailable",
230 "ResourceExhaustion": "service_unavailable",
231 "AccountModified": "ok",
232 "PasswordChangeRequired": None,
233 "ResourceInStandby": "service_unavailable",
234 "GenerateSecretKeyRequired": "forbidden",
235 }
236
237 code = codes.get(entry_id, "NOCODE")
238 if code != "NOCODE":
239 return code
240
241 return "bad_request"
242
243
Ed Tanous7ccfe682024-11-16 14:36:16 -0800244def make_error_function(entry_id, entry, is_header):
Ed Tanous644cdcb2024-11-17 11:12:41 -0800245 arg_nonstring_types = {
246 "const boost::urls::url_view_base&": {
247 "AccessDenied": [1],
248 "CouldNotEstablishConnection": [1],
249 "GenerateSecretKeyRequired": [1],
250 "InvalidObject": [1],
251 "PasswordChangeRequired": [1],
252 "PropertyValueResourceConflict": [3],
253 "ResetRequired": [1],
254 "ResourceAtUriInUnknownFormat": [1],
255 "ResourceAtUriUnauthorized": [1],
256 "ResourceCreationConflict": [1],
257 "ResourceMissingAtURI": [1],
258 "SourceDoesNotSupportProtocol": [1],
259 },
260 "const nlohmann::json&": {
261 "ActionParameterValueError": [1],
262 "ActionParameterValueFormatError": [1],
263 "ActionParameterValueTypeError": [1],
264 "PropertyValueExternalConflict": [2],
265 "PropertyValueFormatError": [1],
266 "PropertyValueIncorrect": [2],
267 "PropertyValueModified": [2],
268 "PropertyValueNotInList": [1],
269 "PropertyValueOutOfRange": [1],
270 "PropertyValueResourceConflict": [2],
271 "PropertyValueTypeError": [1],
272 "QueryParameterValueFormatError": [1],
273 "QueryParameterValueTypeError": [1],
274 },
275 "uint64_t": {
276 "ArraySizeTooLong": [2],
277 "InvalidIndex": [1],
278 "StringValueTooLong": [2],
279 },
Ed Tanous42079ec2024-11-16 13:32:29 -0800280 }
281
Ed Tanous7ccfe682024-11-16 14:36:16 -0800282 out = ""
283 args = []
284 argtypes = []
285 for arg_index, arg in enumerate(entry.get("ParamTypes", [])):
286 arg_index += 1
Ed Tanous644cdcb2024-11-17 11:12:41 -0800287 typename = "std::string_view"
288 for typestring, entries in arg_nonstring_types.items():
289 if arg_index in entries.get(entry_id, []):
290 typename = typestring
291
Ed Tanous7ccfe682024-11-16 14:36:16 -0800292 argtypes.append(typename)
293 args.append(f"{typename} arg{arg_index}")
294 function_name = entry_id[0].lower() + entry_id[1:]
295 arg = ", ".join(args)
296 out += f"nlohmann::json {function_name}({arg})"
297
298 if is_header:
299 out += ";\n\n"
300 else:
301 out += "\n{\n"
302 to_array_type = ""
303 if argtypes:
304 outargs = []
305 for index, typename in enumerate(argtypes):
306 index += 1
307 if typename == "const nlohmann::json&":
308 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 -0800309 elif typename == "uint64_t":
Ed Tanous7ccfe682024-11-16 14:36:16 -0800310 out += f"std::string arg{index}Str = std::to_string(arg{index});\n"
311
312 for index, typename in enumerate(argtypes):
313 index += 1
314 if typename == "const boost::urls::url_view_base&":
315 outargs.append(f"arg{index}.buffer()")
316 to_array_type = "<std::string_view>"
317 elif typename == "const nlohmann::json&":
318 outargs.append(f"arg{index}Str")
319 to_array_type = "<std::string_view>"
Ed Tanous644cdcb2024-11-17 11:12:41 -0800320 elif typename == "uint64_t":
Ed Tanous7ccfe682024-11-16 14:36:16 -0800321 outargs.append(f"arg{index}Str")
322 to_array_type = "<std::string_view>"
323 else:
324 outargs.append(f"arg{index}")
325 argstring = ", ".join(outargs)
Ed Tanous7ccfe682024-11-16 14:36:16 -0800326
327 if argtypes:
328 arg_param = f"std::to_array{to_array_type}({{{argstring}}})"
329 else:
330 arg_param = "{}"
331 out += f" return getLog(redfish::registries::base::Index::{function_name}, {arg_param});"
332 out += "\n}\n\n"
333 args.insert(0, "crow::Response& res")
334 if entry_id == "InternalError":
335 if is_header:
336 args.append(
337 "std::source_location location = std::source_location::current()"
338 )
339 else:
340 args.append("const std::source_location location")
341 arg = ", ".join(args)
342 out += f"void {function_name}({arg})"
343 if is_header:
344 out += ";\n"
345 else:
346 out += "\n{\n"
347 if entry_id == "InternalError":
348 out += """BMCWEB_LOG_CRITICAL("Internal Error {}({}:{}) `{}`: ", location.file_name(),
349 location.line(), location.column(),
350 location.function_name());\n"""
351
352 if entry_id == "ServiceTemporarilyUnavailable":
353 out += (
354 "res.addHeader(boost::beast::http::field::retry_after, arg1);"
355 )
356
357 res = get_response_code(entry_id, entry)
358 if res:
359 out += f" res.result(boost::beast::http::status::{res});\n"
360 args_out = ", ".join([f"arg{x+1}" for x in range(len(argtypes))])
361
362 addMessageToJson = {
363 "PropertyDuplicate": 1,
364 "ResourceAlreadyExists": 2,
365 "CreateFailedMissingReqProperties": 1,
366 "PropertyValueFormatError": 2,
367 "PropertyValueNotInList": 2,
368 "PropertyValueTypeError": 2,
369 "PropertyValueError": 1,
370 "PropertyNotWritable": 1,
371 "PropertyValueModified": 1,
372 "PropertyMissing": 1,
373 }
374
375 addMessageToRoot = [
376 "SessionTerminated",
377 "SubscriptionTerminated",
378 "AccountRemoved",
379 "Created",
380 "Success",
381 "PasswordChangeRequired",
382 ]
383
384 if entry_id in addMessageToJson:
385 out += f" addMessageToJson(res.jsonValue, {function_name}({args_out}), arg{addMessageToJson[entry_id]});\n"
386 elif entry_id in addMessageToRoot:
387 out += f" addMessageToJsonRoot(res.jsonValue, {function_name}({args_out}));\n"
388 else:
389 out += f" addMessageToErrorJson(res.jsonValue, {function_name}({args_out}));\n"
390 out += "}\n"
391 out += "\n"
392 return out
393
394
Ed Tanous352945b2024-11-17 22:45:51 -0800395def create_error_registry(entry, registry_version):
Ed Tanous42079ec2024-11-16 13:32:29 -0800396 file, json_dict, namespace, url = entry
397
Ed Tanous42079ec2024-11-16 13:32:29 -0800398 error_messages_hpp = os.path.join(
399 SCRIPT_DIR, "..", "redfish-core", "include", "error_messages.hpp"
400 )
Ed Tanousf8cca872024-11-16 22:47:34 -0800401 messages = json_dict["Messages"]
402
Ed Tanous42079ec2024-11-16 13:32:29 -0800403 with open(
404 error_messages_hpp,
405 "w",
406 ) as out:
407 out.write(PRAGMA_ONCE)
408 out.write(WARNING)
409 out.write(
410 """
411
412#include "http_response.hpp"
413
414#include <boost/url/url_view_base.hpp>
415#include <nlohmann/json.hpp>
416
417#include <cstdint>
418#include <source_location>
419#include <string>
420#include <string_view>
421
422// IWYU pragma: no_forward_declare crow::Response
423
424namespace redfish
425{
426
427namespace messages
428{
Ed Tanous42079ec2024-11-16 13:32:29 -0800429"""
430 )
Ed Tanous352945b2024-11-17 22:45:51 -0800431 out.write(
432 f'constexpr const char* messageVersionPrefix = "Base.{registry_version}.";'
433 )
434 out.write(
435 """
436 constexpr const char* messageAnnotation = "@Message.ExtendedInfo";
Ed Tanous42079ec2024-11-16 13:32:29 -0800437
Ed Tanous352945b2024-11-17 22:45:51 -0800438 /**
439 * @brief Moves all error messages from the |source| JSON to |target|
440 */
441 void moveErrorsToErrorJson(nlohmann::json& target, nlohmann::json& source);
442
443 """
444 )
Ed Tanous42079ec2024-11-16 13:32:29 -0800445 for entry_id, entry in messages.items():
446 message = entry["Message"]
447 for index in range(1, 10):
448 message = message.replace(f"'%{index}'", f"<arg{index}>")
449 message = message.replace(f"%{index}", f"<arg{index}>")
450
451 out.write("/**\n")
452 out.write(f"* @brief Formats {entry_id} message into JSON\n")
453 out.write(f'* Message body: "{message}"\n')
454 out.write("*\n")
455 arg_index = 0
456 for arg_index, arg in enumerate(entry.get("ParamTypes", [])):
457 arg_index += 1
458
459 out.write(
460 f"* @param[in] arg{arg_index} Parameter of message that will replace %{arg_index} in its body.\n"
461 )
462 out.write("*\n")
463 out.write(f"* @returns Message {entry_id} formatted to JSON */\n")
464
Ed Tanous7ccfe682024-11-16 14:36:16 -0800465 out.write(make_error_function(entry_id, entry, True))
Ed Tanous42079ec2024-11-16 13:32:29 -0800466 out.write(" }\n")
467 out.write("}\n")
Ed Tanous7ccfe682024-11-16 14:36:16 -0800468
469 error_messages_cpp = os.path.join(
470 SCRIPT_DIR, "..", "redfish-core", "src", "error_messages.cpp"
471 )
472 with open(
473 error_messages_cpp,
474 "w",
475 ) as out:
476 out.write(WARNING)
477 out.write(
478 """
479#include "error_messages.hpp"
480
481#include "http_response.hpp"
482#include "logging.hpp"
483#include "registries.hpp"
484#include "registries/base_message_registry.hpp"
485
486#include <boost/beast/http/field.hpp>
487#include <boost/beast/http/status.hpp>
488#include <boost/url/url_view_base.hpp>
489#include <nlohmann/json.hpp>
490
491#include <array>
492#include <cstddef>
493#include <cstdint>
494#include <source_location>
495#include <span>
496#include <string>
497#include <string_view>
498
499// Clang can't seem to decide whether this header needs to be included or not,
500// and is inconsistent. Include it for now
501// NOLINTNEXTLINE(misc-include-cleaner)
502#include <utility>
503
504namespace redfish
505{
506
507namespace messages
508{
509
510static void addMessageToErrorJson(nlohmann::json& target,
511 const nlohmann::json& message)
512{
513 auto& error = target["error"];
514
515 // If this is the first error message, fill in the information from the
516 // first error message to the top level struct
517 if (!error.is_object())
518 {
519 auto messageIdIterator = message.find("MessageId");
520 if (messageIdIterator == message.end())
521 {
522 BMCWEB_LOG_CRITICAL(
523 "Attempt to add error message without MessageId");
524 return;
525 }
526
527 auto messageFieldIterator = message.find("Message");
528 if (messageFieldIterator == message.end())
529 {
530 BMCWEB_LOG_CRITICAL("Attempt to add error message without Message");
531 return;
532 }
533 error["code"] = *messageIdIterator;
534 error["message"] = *messageFieldIterator;
535 }
536 else
537 {
538 // More than 1 error occurred, so the message has to be generic
539 error["code"] = std::string(messageVersionPrefix) + "GeneralError";
540 error["message"] = "A general error has occurred. See Resolution for "
541 "information on how to resolve the error.";
542 }
543
544 // This check could technically be done in the default construction
545 // branch above, but because we need the pointer to the extended info field
546 // anyway, it's more efficient to do it here.
547 auto& extendedInfo = error[messages::messageAnnotation];
548 if (!extendedInfo.is_array())
549 {
550 extendedInfo = nlohmann::json::array();
551 }
552
553 extendedInfo.push_back(message);
554}
555
556void moveErrorsToErrorJson(nlohmann::json& target, nlohmann::json& source)
557{
558 if (!source.is_object())
559 {
560 return;
561 }
562 auto errorIt = source.find("error");
563 if (errorIt == source.end())
564 {
565 // caller puts error message in root
566 messages::addMessageToErrorJson(target, source);
567 source.clear();
568 return;
569 }
570 auto extendedInfoIt = errorIt->find(messages::messageAnnotation);
571 if (extendedInfoIt == errorIt->end())
572 {
573 return;
574 }
575 const nlohmann::json::array_t* extendedInfo =
576 (*extendedInfoIt).get_ptr<const nlohmann::json::array_t*>();
577 if (extendedInfo == nullptr)
578 {
579 source.erase(errorIt);
580 return;
581 }
582 for (const nlohmann::json& message : *extendedInfo)
583 {
584 addMessageToErrorJson(target, message);
585 }
586 source.erase(errorIt);
587}
588
589static void addMessageToJsonRoot(nlohmann::json& target,
590 const nlohmann::json& message)
591{
592 if (!target[messages::messageAnnotation].is_array())
593 {
594 // Force object to be an array
595 target[messages::messageAnnotation] = nlohmann::json::array();
596 }
597
598 target[messages::messageAnnotation].push_back(message);
599}
600
601static void addMessageToJson(nlohmann::json& target,
602 const nlohmann::json& message,
603 std::string_view fieldPath)
604{
605 std::string extendedInfo(fieldPath);
606 extendedInfo += messages::messageAnnotation;
607
608 nlohmann::json& field = target[extendedInfo];
609 if (!field.is_array())
610 {
611 // Force object to be an array
612 field = nlohmann::json::array();
613 }
614
615 // Object exists and it is an array so we can just push in the message
616 field.push_back(message);
617}
618
619static nlohmann::json getLog(redfish::registries::base::Index name,
620 std::span<const std::string_view> args)
621{
622 size_t index = static_cast<size_t>(name);
623 if (index >= redfish::registries::base::registry.size())
624 {
625 return {};
626 }
627 return getLogFromRegistry(redfish::registries::base::header,
628 redfish::registries::base::registry, index, args);
629}
630
631"""
632 )
633 for entry_id, entry in messages.items():
634 out.write(
635 f"""/**
636 * @internal
637 * @brief Formats {entry_id} message into JSON
638 *
639 * See header file for more information
640 * @endinternal
641 */
642"""
643 )
644 message = entry["Message"]
645 out.write(make_error_function(entry_id, entry, False))
646
647 out.write(" }\n")
648 out.write("}\n")
649 os.system(f"clang-format -i {error_messages_hpp} {error_messages_cpp}")
Ed Tanous42079ec2024-11-16 13:32:29 -0800650
651
Ed Tanoused398212021-06-09 17:05:54 -0700652def make_privilege_registry():
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600653 path, json_file, type_name, url = make_getter(
Gunnar Mills5910d942024-04-16 12:07:17 -0500654 "Redfish_1.5.0_PrivilegeRegistry.json",
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600655 "privilege_registry.hpp",
656 "privilege",
657 )
658 with open(path, "w") as registry:
Nan Zhou043bec02022-09-20 18:12:13 +0000659 registry.write(PRIVILEGE_HEADER)
Ed Tanoused398212021-06-09 17:05:54 -0700660
661 privilege_dict = {}
662 for mapping in json_file["Mappings"]:
663 # first pass, identify all the unique privilege sets
664 for operation, privilege_list in mapping["OperationMap"].items():
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600665 privilege_dict[
666 get_privilege_string_from_list(privilege_list)
667 ] = (privilege_list,)
Ed Tanoused398212021-06-09 17:05:54 -0700668 for index, key in enumerate(privilege_dict):
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600669 (privilege_list,) = privilege_dict[key]
Ed Tanoused398212021-06-09 17:05:54 -0700670 name = get_variable_name_for_privilege_set(privilege_list)
Ed Tanousf395daa2021-08-02 08:56:24 -0700671 registry.write(
Ed Tanous5b9ef702022-02-17 12:19:32 -0800672 "const std::array<Privileges, {length}> "
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600673 "privilegeSet{name} = {key};\n".format(
674 length=len(privilege_list), name=name, key=key
675 )
Ed Tanous5b9ef702022-02-17 12:19:32 -0800676 )
Ed Tanoused398212021-06-09 17:05:54 -0700677 privilege_dict[key] = (privilege_list, name)
Ed Tanoused398212021-06-09 17:05:54 -0700678
679 for mapping in json_file["Mappings"]:
680 entity = mapping["Entity"]
Ed Tanous4d99bbb2022-02-17 10:02:57 -0800681 registry.write("// {}\n".format(entity))
Ed Tanoused398212021-06-09 17:05:54 -0700682 for operation, privilege_list in mapping["OperationMap"].items():
683 privilege_string = get_privilege_string_from_list(
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600684 privilege_list
685 )
Ed Tanoused398212021-06-09 17:05:54 -0700686 operation = operation.lower()
687
Ed Tanousf395daa2021-08-02 08:56:24 -0700688 registry.write(
689 "const static auto& {}{} = privilegeSet{};\n".format(
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600690 operation, entity, privilege_dict[privilege_string][1]
691 )
692 )
Ed Tanoused398212021-06-09 17:05:54 -0700693 registry.write("\n")
Ed Tanous5b9ef702022-02-17 12:19:32 -0800694 registry.write(
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600695 "} // namespace redfish::privileges\n// clang-format on\n"
696 )
Ed Tanoused398212021-06-09 17:05:54 -0700697
698
Gunnar Mills665e7602024-04-10 13:14:41 -0500699def to_pascal_case(text):
700 s = text.replace("_", " ")
701 s = s.split()
702 if len(text) == 0:
703 return text
704 return "".join(i.capitalize() for i in s[0:])
705
706
Nan Zhou49aa131f2022-09-20 18:41:37 +0000707def main():
Gunnar Mills665e7602024-04-10 13:14:41 -0500708 dmtf_registries = (
Jishnu CMb575cae2024-10-01 01:33:49 -0500709 ("base", "1.19.0"),
Gunnar Mills665e7602024-04-10 13:14:41 -0500710 ("composition", "1.1.2"),
711 ("environmental", "1.0.1"),
712 ("ethernet_fabric", "1.0.1"),
713 ("fabric", "1.0.2"),
714 ("heartbeat_event", "1.0.1"),
715 ("job_event", "1.0.1"),
716 ("license", "1.0.3"),
717 ("log_service", "1.0.1"),
718 ("network_device", "1.0.3"),
719 ("platform", "1.0.1"),
720 ("power", "1.0.1"),
721 ("resource_event", "1.3.0"),
722 ("sensor_event", "1.0.1"),
723 ("storage_device", "1.2.1"),
724 ("task_event", "1.0.3"),
725 ("telemetry", "1.0.0"),
726 ("update", "1.0.2"),
727 )
728
Nan Zhou49aa131f2022-09-20 18:41:37 +0000729 parser = argparse.ArgumentParser()
730 parser.add_argument(
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600731 "--registries",
732 type=str,
Gunnar Mills665e7602024-04-10 13:14:41 -0500733 default="privilege,openbmc,"
734 + ",".join([dmtf[0] for dmtf in dmtf_registries]),
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600735 help="Comma delimited list of registries to update",
736 )
Nan Zhou49aa131f2022-09-20 18:41:37 +0000737
738 args = parser.parse_args()
739
740 registries = set(args.registries.split(","))
741 files = []
742
Gunnar Mills665e7602024-04-10 13:14:41 -0500743 for registry, version in dmtf_registries:
744 if registry in registries:
745 registry_pascal_case = to_pascal_case(registry)
746 files.append(
747 make_getter(
748 f"{registry_pascal_case}.{version}.json",
749 f"{registry}_message_registry.hpp",
750 registry,
751 )
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600752 )
Ed Tanous3e5faba2023-08-16 15:11:29 -0700753 if "openbmc" in registries:
754 files.append(openbmc_local_getter())
Nan Zhou49aa131f2022-09-20 18:41:37 +0000755
756 update_registries(files)
757
Ed Tanous352945b2024-11-17 22:45:51 -0800758 create_error_registry(files[0], dmtf_registries[0][1])
Ed Tanous42079ec2024-11-16 13:32:29 -0800759
Nan Zhou49aa131f2022-09-20 18:41:37 +0000760 if "privilege" in registries:
761 make_privilege_registry()
762
763
764if __name__ == "__main__":
765 main()