blob: 573f8a705bad8dda2f89e3fab197b5d3f6798802 [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():
57 url = ""
58 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:
Nan Zhou49aa131f2022-09-20 18:41:37 +000084 registry.write(REGISTRY_HEADER.format(namespace))
85 # Parse the Registry header info
Ed Tanous5b9ef702022-02-17 12:19:32 -080086 registry.write(
Nan Zhou49aa131f2022-09-20 18:41:37 +000087 "const Header header = {{\n"
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -060088 ' "{json_dict[@Redfish.Copyright]}",\n'
89 ' "{json_dict[@odata.type]}",\n'
90 ' "{json_dict[Id]}",\n'
91 ' "{json_dict[Name]}",\n'
92 ' "{json_dict[Language]}",\n'
93 ' "{json_dict[Description]}",\n'
94 ' "{json_dict[RegistryPrefix]}",\n'
95 ' "{json_dict[RegistryVersion]}",\n'
96 ' "{json_dict[OwningEntity]}",\n'
Nan Zhou49aa131f2022-09-20 18:41:37 +000097 "}};\n"
98 "constexpr const char* url =\n"
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -060099 ' "{url}";\n'
Nan Zhou49aa131f2022-09-20 18:41:37 +0000100 "\n"
101 "constexpr std::array registry =\n"
102 "{{\n".format(
103 json_dict=json_dict,
104 url=url,
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600105 )
106 )
Ed Tanous30a3c432022-02-07 09:37:21 -0800107
Nan Zhou49aa131f2022-09-20 18:41:37 +0000108 messages_sorted = sorted(json_dict["Messages"].items())
109 for messageId, message in messages_sorted:
110 registry.write(
111 " MessageEntry{{\n"
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600112 ' "{messageId}",\n'
Nan Zhou49aa131f2022-09-20 18:41:37 +0000113 " {{\n"
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600114 ' "{message[Description]}",\n'
115 ' "{message[Message]}",\n'
116 ' "{message[MessageSeverity]}",\n'
Nan Zhou49aa131f2022-09-20 18:41:37 +0000117 " {message[NumberOfArgs]},\n"
118 " {{".format(
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600119 messageId=messageId, message=message
120 )
121 )
Nan Zhou49aa131f2022-09-20 18:41:37 +0000122 paramTypes = message.get("ParamTypes")
123 if paramTypes:
124 for paramType in paramTypes:
125 registry.write(
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600126 '\n "{}",'.format(paramType)
Nan Zhou49aa131f2022-09-20 18:41:37 +0000127 )
128 registry.write("\n },\n")
129 else:
130 registry.write("},\n")
131 registry.write(
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600132 ' "{message[Resolution]}",\n'
133 " }}}},\n".format(message=message)
134 )
Nan Zhou49aa131f2022-09-20 18:41:37 +0000135
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600136 registry.write("\n};\n\nenum class Index\n{\n")
Nan Zhou49aa131f2022-09-20 18:41:37 +0000137 for index, (messageId, message) in enumerate(messages_sorted):
138 messageId = messageId[0].lower() + messageId[1:]
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600139 registry.write(" {} = {},\n".format(messageId, index))
Nan Zhou49aa131f2022-09-20 18:41:37 +0000140 registry.write(
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600141 "}};\n}} // namespace redfish::registries::{}\n".format(
142 namespace
143 )
144 )
Ed Tanoused398212021-06-09 17:05:54 -0700145
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
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600155 privilege_string += '"'
Ed Tanoused398212021-06-09 17:05:54 -0700156 privilege_string += privilege
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600157 privilege_string += '",\n'
Ed Tanoused398212021-06-09 17:05:54 -0700158 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
Ed Tanousf395daa2021-08-02 08:56:24 -0700166
Ed Tanoused398212021-06-09 17:05:54 -0700167def 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
Ed Tanousf395daa2021-08-02 08:56:24 -0700174
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600175PRIVILEGE_HEADER = (
176 PRAGMA_ONCE
177 + WARNING
178 + """
Nan Zhou01c78a02022-09-20 18:17:20 +0000179#include "privileges.hpp"
180
181#include <array>
Nan Zhou043bec02022-09-20 18:12:13 +0000182
183// clang-format off
184
185namespace redfish::privileges
186{
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600187"""
188)
Nan Zhou043bec02022-09-20 18:12:13 +0000189
190
Ed Tanous7ccfe682024-11-16 14:36:16 -0800191def get_response_code(entry_id, entry):
192 codes = {
193 "InternalError": "internal_server_error",
194 "OperationTimeout": "internal_server_error",
195 "PropertyValueResourceConflict": "conflict",
196 "ResourceInUse": "service_unavailable",
197 "ServiceTemporarilyUnavailable": "service_unavailable",
198 "ResourceCannotBeDeleted": "method_not_allowed",
199 "PropertyValueModified": "ok",
200 "InsufficientPrivilege": "forbidden",
201 "AccountForSessionNoLongerExists": "forbidden",
202 "ServiceDisabled": "service_unavailable",
203 "ServiceInUnknownState": "service_unavailable",
204 "EventSubscriptionLimitExceeded": "service_unavailable",
205 "ResourceAtUriUnauthorized": "unauthorized",
206 "SessionTerminated": "ok",
207 "SubscriptionTerminated": "ok",
208 "PropertyNotWritable": "forbidden",
209 "MaximumErrorsExceeded": "internal_server_error",
210 "GeneralError": "internal_server_error",
211 "PreconditionFailed": "precondition_failed",
212 "OperationFailed": "bad_gateway",
213 "ServiceShuttingDown": "service_unavailable",
214 "AccountRemoved": "ok",
215 "PropertyValueExternalConflict": "conflict",
216 "InsufficientStorage": "insufficient_storage",
217 "OperationNotAllowed": "method_not_allowed",
218 "ResourceNotFound": "not_found",
219 "CouldNotEstablishConnection": "not_found",
220 "AccessDenied": "forbidden",
221 "Success": None,
222 "Created": "created",
223 "NoValidSession": "forbidden",
224 "SessionLimitExceeded": "service_unavailable",
225 "ResourceExhaustion": "service_unavailable",
226 "AccountModified": "ok",
227 "PasswordChangeRequired": None,
228 "ResourceInStandby": "service_unavailable",
229 "GenerateSecretKeyRequired": "forbidden",
230 }
231
232 code = codes.get(entry_id, "NOCODE")
233 if code != "NOCODE":
234 return code
235
236 return "bad_request"
237
238
Ed Tanous42079ec2024-11-16 13:32:29 -0800239def get_old_index(entry):
240 old_order = [
241 "ResourceInUse",
242 "MalformedJSON",
243 "ResourceMissingAtURI",
244 "ActionParameterValueFormatError",
245 "ActionParameterValueNotInList",
246 "InternalError",
247 "UnrecognizedRequestBody",
248 "ResourceAtUriUnauthorized",
249 "ActionParameterUnknown",
250 "ResourceCannotBeDeleted",
251 "PropertyDuplicate",
252 "ServiceTemporarilyUnavailable",
253 "ResourceAlreadyExists",
254 "AccountForSessionNoLongerExists",
255 "CreateFailedMissingReqProperties",
256 "PropertyValueFormatError",
257 "PropertyValueNotInList",
258 "PropertyValueOutOfRange",
259 "ResourceAtUriInUnknownFormat",
260 "ServiceDisabled",
261 "ServiceInUnknownState",
262 "EventSubscriptionLimitExceeded",
263 "ActionParameterMissing",
264 "StringValueTooLong",
265 "SessionTerminated",
266 "SubscriptionTerminated",
267 "ResourceTypeIncompatible",
268 "ResetRequired",
269 "ChassisPowerStateOnRequired",
270 "ChassisPowerStateOffRequired",
271 "PropertyValueConflict",
272 "PropertyValueResourceConflict",
273 "PropertyValueExternalConflict",
274 "PropertyValueIncorrect",
275 "ResourceCreationConflict",
276 "MaximumErrorsExceeded",
277 "PreconditionFailed",
278 "PreconditionRequired",
279 "OperationFailed",
280 "OperationTimeout",
281 "PropertyValueTypeError",
282 "PropertyValueError",
283 "ResourceNotFound",
284 "CouldNotEstablishConnection",
285 "PropertyNotWritable",
286 "QueryParameterValueTypeError",
287 "ServiceShuttingDown",
288 "ActionParameterDuplicate",
289 "ActionParameterNotSupported",
290 "SourceDoesNotSupportProtocol",
291 "StrictAccountTypes",
292 "AccountRemoved",
293 "AccessDenied",
294 "QueryNotSupported",
295 "CreateLimitReachedForResource",
296 "GeneralError",
297 "Success",
298 "Created",
299 "NoOperation",
300 "PropertyUnknown",
301 "NoValidSession",
302 "InvalidObject",
303 "ResourceInStandby",
304 "ActionParameterValueTypeError",
305 "ActionParameterValueError",
306 "SessionLimitExceeded",
307 "ActionNotSupported",
308 "InvalidIndex",
309 "EmptyJSON",
310 "QueryNotSupportedOnResource",
311 "QueryNotSupportedOnOperation",
312 "QueryCombinationInvalid",
313 "EventBufferExceeded",
314 "InsufficientPrivilege",
315 "PropertyValueModified",
316 "AccountNotModified",
317 "QueryParameterValueFormatError",
318 "PropertyMissing",
319 "ResourceExhaustion",
320 "AccountModified",
321 "QueryParameterOutOfRange",
322 "PasswordChangeRequired",
Ed Tanous42079ec2024-11-16 13:32:29 -0800323 "InsufficientStorage",
324 "OperationNotAllowed",
325 "ArraySizeTooLong",
326 "Invalid File",
327 "GenerateSecretKeyRequired",
328 ]
329
330 if entry[0] in old_order:
331 return old_order.index(entry[0])
332 else:
333 return 999999
334
335
Ed Tanous7ccfe682024-11-16 14:36:16 -0800336def make_error_function(entry_id, entry, is_header):
Ed Tanous42079ec2024-11-16 13:32:29 -0800337
338 arg_as_url = {
339 "AccessDenied": [1],
340 "CouldNotEstablishConnection": [1],
341 "GenerateSecretKeyRequired": [1],
342 "InvalidObject": [1],
343 "PasswordChangeRequired": [1],
344 "PropertyValueResourceConflict": [3],
345 "ResetRequired": [1],
346 "ResourceAtUriInUnknownFormat": [1],
347 "ResourceAtUriUnauthorized": [1],
348 "ResourceCreationConflict": [1],
349 "ResourceMissingAtURI": [1],
350 "SourceDoesNotSupportProtocol": [1],
351 }
352
353 arg_as_json = {
354 "ActionParameterValueError": [1],
355 "ActionParameterValueFormatError": [1],
356 "ActionParameterValueTypeError": [1],
357 "PropertyValueExternalConflict": [2],
358 "PropertyValueFormatError": [1],
359 "PropertyValueIncorrect": [2],
360 "PropertyValueModified": [2],
361 "PropertyValueNotInList": [1],
362 "PropertyValueOutOfRange": [1],
363 "PropertyValueResourceConflict": [2],
364 "PropertyValueTypeError": [1],
365 "QueryParameterValueFormatError": [1],
366 "QueryParameterValueTypeError": [1],
367 }
368
369 arg_as_int = {
370 "StringValueTooLong": [2],
371 }
372
373 arg_as_uint64 = {
374 "ArraySizeTooLong": [2],
375 }
376 arg_as_int64 = {
377 "InvalidIndex": [1],
378 }
379
Ed Tanous7ccfe682024-11-16 14:36:16 -0800380 out = ""
381 args = []
382 argtypes = []
383 for arg_index, arg in enumerate(entry.get("ParamTypes", [])):
384 arg_index += 1
385 if arg_index in arg_as_url.get(entry_id, []):
386 typename = "const boost::urls::url_view_base&"
387 elif arg_index in arg_as_json.get(entry_id, []):
388 typename = "const nlohmann::json&"
389 elif arg_index in arg_as_int.get(entry_id, []):
390 typename = "int"
391 elif arg_index in arg_as_uint64.get(entry_id, []):
392 typename = "uint64_t"
393 elif arg_index in arg_as_int64.get(entry_id, []):
394 typename = "int64_t"
395 else:
396 typename = "std::string_view"
397 argtypes.append(typename)
398 args.append(f"{typename} arg{arg_index}")
399 function_name = entry_id[0].lower() + entry_id[1:]
400 arg = ", ".join(args)
401 out += f"nlohmann::json {function_name}({arg})"
402
403 if is_header:
404 out += ";\n\n"
405 else:
406 out += "\n{\n"
407 to_array_type = ""
408 if argtypes:
409 outargs = []
410 for index, typename in enumerate(argtypes):
411 index += 1
412 if typename == "const nlohmann::json&":
413 out += f"std::string arg{index}Str = arg{index}.dump(-1, ' ', true, nlohmann::json::error_handler_t::replace);\n"
414 elif typename in ("int64_t", "int", "uint64_t"):
415 out += f"std::string arg{index}Str = std::to_string(arg{index});\n"
416
417 for index, typename in enumerate(argtypes):
418 index += 1
419 if typename == "const boost::urls::url_view_base&":
420 outargs.append(f"arg{index}.buffer()")
421 to_array_type = "<std::string_view>"
422 elif typename == "const nlohmann::json&":
423 outargs.append(f"arg{index}Str")
424 to_array_type = "<std::string_view>"
425 elif typename in ("int64_t", "int", "uint64_t"):
426 outargs.append(f"arg{index}Str")
427 to_array_type = "<std::string_view>"
428 else:
429 outargs.append(f"arg{index}")
430 argstring = ", ".join(outargs)
431 # out += f" std::array<std::string_view, {len(argtypes)}> args{{{argstring}}};\n"
432
433 if argtypes:
434 arg_param = f"std::to_array{to_array_type}({{{argstring}}})"
435 else:
436 arg_param = "{}"
437 out += f" return getLog(redfish::registries::base::Index::{function_name}, {arg_param});"
438 out += "\n}\n\n"
439 args.insert(0, "crow::Response& res")
440 if entry_id == "InternalError":
441 if is_header:
442 args.append(
443 "std::source_location location = std::source_location::current()"
444 )
445 else:
446 args.append("const std::source_location location")
447 arg = ", ".join(args)
448 out += f"void {function_name}({arg})"
449 if is_header:
450 out += ";\n"
451 else:
452 out += "\n{\n"
453 if entry_id == "InternalError":
454 out += """BMCWEB_LOG_CRITICAL("Internal Error {}({}:{}) `{}`: ", location.file_name(),
455 location.line(), location.column(),
456 location.function_name());\n"""
457
458 if entry_id == "ServiceTemporarilyUnavailable":
459 out += (
460 "res.addHeader(boost::beast::http::field::retry_after, arg1);"
461 )
462
463 res = get_response_code(entry_id, entry)
464 if res:
465 out += f" res.result(boost::beast::http::status::{res});\n"
466 args_out = ", ".join([f"arg{x+1}" for x in range(len(argtypes))])
467
468 addMessageToJson = {
469 "PropertyDuplicate": 1,
470 "ResourceAlreadyExists": 2,
471 "CreateFailedMissingReqProperties": 1,
472 "PropertyValueFormatError": 2,
473 "PropertyValueNotInList": 2,
474 "PropertyValueTypeError": 2,
475 "PropertyValueError": 1,
476 "PropertyNotWritable": 1,
477 "PropertyValueModified": 1,
478 "PropertyMissing": 1,
479 }
480
481 addMessageToRoot = [
482 "SessionTerminated",
483 "SubscriptionTerminated",
484 "AccountRemoved",
485 "Created",
486 "Success",
487 "PasswordChangeRequired",
488 ]
489
490 if entry_id in addMessageToJson:
491 out += f" addMessageToJson(res.jsonValue, {function_name}({args_out}), arg{addMessageToJson[entry_id]});\n"
492 elif entry_id in addMessageToRoot:
493 out += f" addMessageToJsonRoot(res.jsonValue, {function_name}({args_out}));\n"
494 else:
495 out += f" addMessageToErrorJson(res.jsonValue, {function_name}({args_out}));\n"
496 out += "}\n"
497 out += "\n"
498 return out
499
500
501def create_error_registry(entry):
Ed Tanous42079ec2024-11-16 13:32:29 -0800502 file, json_dict, namespace, url = entry
503
Ed Tanous42079ec2024-11-16 13:32:29 -0800504 messages = OrderedDict(
505 sorted(json_dict["Messages"].items(), key=get_old_index)
506 )
507 error_messages_hpp = os.path.join(
508 SCRIPT_DIR, "..", "redfish-core", "include", "error_messages.hpp"
509 )
510 with open(
511 error_messages_hpp,
512 "w",
513 ) as out:
514 out.write(PRAGMA_ONCE)
515 out.write(WARNING)
516 out.write(
517 """
518
519#include "http_response.hpp"
520
521#include <boost/url/url_view_base.hpp>
522#include <nlohmann/json.hpp>
523
524#include <cstdint>
525#include <source_location>
526#include <string>
527#include <string_view>
Ed Tanousc87294a2024-11-16 22:17:12 -0800528#include <utility>
Ed Tanous42079ec2024-11-16 13:32:29 -0800529
530// IWYU pragma: no_forward_declare crow::Response
531
532namespace redfish
533{
534
535namespace messages
536{
537
538 constexpr const char* messageVersionPrefix = "Base.1.11.0.";
539 constexpr const char* messageAnnotation = "@Message.ExtendedInfo";
540
541 /**
542 * @brief Moves all error messages from the |source| JSON to |target|
543 */
544 void moveErrorsToErrorJson(nlohmann::json& target, nlohmann::json& source);
545
546"""
547 )
548
549 for entry_id, entry in messages.items():
550 message = entry["Message"]
551 for index in range(1, 10):
552 message = message.replace(f"'%{index}'", f"<arg{index}>")
553 message = message.replace(f"%{index}", f"<arg{index}>")
554
555 out.write("/**\n")
556 out.write(f"* @brief Formats {entry_id} message into JSON\n")
557 out.write(f'* Message body: "{message}"\n')
558 out.write("*\n")
559 arg_index = 0
560 for arg_index, arg in enumerate(entry.get("ParamTypes", [])):
561 arg_index += 1
562
563 out.write(
564 f"* @param[in] arg{arg_index} Parameter of message that will replace %{arg_index} in its body.\n"
565 )
566 out.write("*\n")
567 out.write(f"* @returns Message {entry_id} formatted to JSON */\n")
568
Ed Tanous7ccfe682024-11-16 14:36:16 -0800569 out.write(make_error_function(entry_id, entry, True))
Ed Tanous42079ec2024-11-16 13:32:29 -0800570 out.write(" }\n")
571 out.write("}\n")
Ed Tanous7ccfe682024-11-16 14:36:16 -0800572
573 error_messages_cpp = os.path.join(
574 SCRIPT_DIR, "..", "redfish-core", "src", "error_messages.cpp"
575 )
576 with open(
577 error_messages_cpp,
578 "w",
579 ) as out:
580 out.write(WARNING)
581 out.write(
582 """
583#include "error_messages.hpp"
584
585#include "http_response.hpp"
586#include "logging.hpp"
587#include "registries.hpp"
588#include "registries/base_message_registry.hpp"
589
590#include <boost/beast/http/field.hpp>
591#include <boost/beast/http/status.hpp>
592#include <boost/url/url_view_base.hpp>
593#include <nlohmann/json.hpp>
594
595#include <array>
596#include <cstddef>
597#include <cstdint>
598#include <source_location>
599#include <span>
600#include <string>
601#include <string_view>
602
603// Clang can't seem to decide whether this header needs to be included or not,
604// and is inconsistent. Include it for now
605// NOLINTNEXTLINE(misc-include-cleaner)
606#include <utility>
607
608namespace redfish
609{
610
611namespace messages
612{
613
614static void addMessageToErrorJson(nlohmann::json& target,
615 const nlohmann::json& message)
616{
617 auto& error = target["error"];
618
619 // If this is the first error message, fill in the information from the
620 // first error message to the top level struct
621 if (!error.is_object())
622 {
623 auto messageIdIterator = message.find("MessageId");
624 if (messageIdIterator == message.end())
625 {
626 BMCWEB_LOG_CRITICAL(
627 "Attempt to add error message without MessageId");
628 return;
629 }
630
631 auto messageFieldIterator = message.find("Message");
632 if (messageFieldIterator == message.end())
633 {
634 BMCWEB_LOG_CRITICAL("Attempt to add error message without Message");
635 return;
636 }
637 error["code"] = *messageIdIterator;
638 error["message"] = *messageFieldIterator;
639 }
640 else
641 {
642 // More than 1 error occurred, so the message has to be generic
643 error["code"] = std::string(messageVersionPrefix) + "GeneralError";
644 error["message"] = "A general error has occurred. See Resolution for "
645 "information on how to resolve the error.";
646 }
647
648 // This check could technically be done in the default construction
649 // branch above, but because we need the pointer to the extended info field
650 // anyway, it's more efficient to do it here.
651 auto& extendedInfo = error[messages::messageAnnotation];
652 if (!extendedInfo.is_array())
653 {
654 extendedInfo = nlohmann::json::array();
655 }
656
657 extendedInfo.push_back(message);
658}
659
660void moveErrorsToErrorJson(nlohmann::json& target, nlohmann::json& source)
661{
662 if (!source.is_object())
663 {
664 return;
665 }
666 auto errorIt = source.find("error");
667 if (errorIt == source.end())
668 {
669 // caller puts error message in root
670 messages::addMessageToErrorJson(target, source);
671 source.clear();
672 return;
673 }
674 auto extendedInfoIt = errorIt->find(messages::messageAnnotation);
675 if (extendedInfoIt == errorIt->end())
676 {
677 return;
678 }
679 const nlohmann::json::array_t* extendedInfo =
680 (*extendedInfoIt).get_ptr<const nlohmann::json::array_t*>();
681 if (extendedInfo == nullptr)
682 {
683 source.erase(errorIt);
684 return;
685 }
686 for (const nlohmann::json& message : *extendedInfo)
687 {
688 addMessageToErrorJson(target, message);
689 }
690 source.erase(errorIt);
691}
692
693static void addMessageToJsonRoot(nlohmann::json& target,
694 const nlohmann::json& message)
695{
696 if (!target[messages::messageAnnotation].is_array())
697 {
698 // Force object to be an array
699 target[messages::messageAnnotation] = nlohmann::json::array();
700 }
701
702 target[messages::messageAnnotation].push_back(message);
703}
704
705static void addMessageToJson(nlohmann::json& target,
706 const nlohmann::json& message,
707 std::string_view fieldPath)
708{
709 std::string extendedInfo(fieldPath);
710 extendedInfo += messages::messageAnnotation;
711
712 nlohmann::json& field = target[extendedInfo];
713 if (!field.is_array())
714 {
715 // Force object to be an array
716 field = nlohmann::json::array();
717 }
718
719 // Object exists and it is an array so we can just push in the message
720 field.push_back(message);
721}
722
723static nlohmann::json getLog(redfish::registries::base::Index name,
724 std::span<const std::string_view> args)
725{
726 size_t index = static_cast<size_t>(name);
727 if (index >= redfish::registries::base::registry.size())
728 {
729 return {};
730 }
731 return getLogFromRegistry(redfish::registries::base::header,
732 redfish::registries::base::registry, index, args);
733}
734
735"""
736 )
737 for entry_id, entry in messages.items():
738 out.write(
739 f"""/**
740 * @internal
741 * @brief Formats {entry_id} message into JSON
742 *
743 * See header file for more information
744 * @endinternal
745 */
746"""
747 )
748 message = entry["Message"]
749 out.write(make_error_function(entry_id, entry, False))
750
751 out.write(" }\n")
752 out.write("}\n")
753 os.system(f"clang-format -i {error_messages_hpp} {error_messages_cpp}")
Ed Tanous42079ec2024-11-16 13:32:29 -0800754
755
Ed Tanoused398212021-06-09 17:05:54 -0700756def make_privilege_registry():
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600757 path, json_file, type_name, url = make_getter(
Gunnar Mills5910d942024-04-16 12:07:17 -0500758 "Redfish_1.5.0_PrivilegeRegistry.json",
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600759 "privilege_registry.hpp",
760 "privilege",
761 )
762 with open(path, "w") as registry:
Nan Zhou043bec02022-09-20 18:12:13 +0000763 registry.write(PRIVILEGE_HEADER)
Ed Tanoused398212021-06-09 17:05:54 -0700764
765 privilege_dict = {}
766 for mapping in json_file["Mappings"]:
767 # first pass, identify all the unique privilege sets
768 for operation, privilege_list in mapping["OperationMap"].items():
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600769 privilege_dict[
770 get_privilege_string_from_list(privilege_list)
771 ] = (privilege_list,)
Ed Tanoused398212021-06-09 17:05:54 -0700772 for index, key in enumerate(privilege_dict):
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600773 (privilege_list,) = privilege_dict[key]
Ed Tanoused398212021-06-09 17:05:54 -0700774 name = get_variable_name_for_privilege_set(privilege_list)
Ed Tanousf395daa2021-08-02 08:56:24 -0700775 registry.write(
Ed Tanous5b9ef702022-02-17 12:19:32 -0800776 "const std::array<Privileges, {length}> "
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600777 "privilegeSet{name} = {key};\n".format(
778 length=len(privilege_list), name=name, key=key
779 )
Ed Tanous5b9ef702022-02-17 12:19:32 -0800780 )
Ed Tanoused398212021-06-09 17:05:54 -0700781 privilege_dict[key] = (privilege_list, name)
Ed Tanoused398212021-06-09 17:05:54 -0700782
783 for mapping in json_file["Mappings"]:
784 entity = mapping["Entity"]
Ed Tanous4d99bbb2022-02-17 10:02:57 -0800785 registry.write("// {}\n".format(entity))
Ed Tanoused398212021-06-09 17:05:54 -0700786 for operation, privilege_list in mapping["OperationMap"].items():
787 privilege_string = get_privilege_string_from_list(
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600788 privilege_list
789 )
Ed Tanoused398212021-06-09 17:05:54 -0700790 operation = operation.lower()
791
Ed Tanousf395daa2021-08-02 08:56:24 -0700792 registry.write(
793 "const static auto& {}{} = privilegeSet{};\n".format(
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600794 operation, entity, privilege_dict[privilege_string][1]
795 )
796 )
Ed Tanoused398212021-06-09 17:05:54 -0700797 registry.write("\n")
Ed Tanous5b9ef702022-02-17 12:19:32 -0800798 registry.write(
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600799 "} // namespace redfish::privileges\n// clang-format on\n"
800 )
Ed Tanoused398212021-06-09 17:05:54 -0700801
802
Gunnar Mills665e7602024-04-10 13:14:41 -0500803def to_pascal_case(text):
804 s = text.replace("_", " ")
805 s = s.split()
806 if len(text) == 0:
807 return text
808 return "".join(i.capitalize() for i in s[0:])
809
810
Nan Zhou49aa131f2022-09-20 18:41:37 +0000811def main():
Gunnar Mills665e7602024-04-10 13:14:41 -0500812 dmtf_registries = (
Jishnu CMb575cae2024-10-01 01:33:49 -0500813 ("base", "1.19.0"),
Gunnar Mills665e7602024-04-10 13:14:41 -0500814 ("composition", "1.1.2"),
815 ("environmental", "1.0.1"),
816 ("ethernet_fabric", "1.0.1"),
817 ("fabric", "1.0.2"),
818 ("heartbeat_event", "1.0.1"),
819 ("job_event", "1.0.1"),
820 ("license", "1.0.3"),
821 ("log_service", "1.0.1"),
822 ("network_device", "1.0.3"),
823 ("platform", "1.0.1"),
824 ("power", "1.0.1"),
825 ("resource_event", "1.3.0"),
826 ("sensor_event", "1.0.1"),
827 ("storage_device", "1.2.1"),
828 ("task_event", "1.0.3"),
829 ("telemetry", "1.0.0"),
830 ("update", "1.0.2"),
831 )
832
Nan Zhou49aa131f2022-09-20 18:41:37 +0000833 parser = argparse.ArgumentParser()
834 parser.add_argument(
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600835 "--registries",
836 type=str,
Gunnar Mills665e7602024-04-10 13:14:41 -0500837 default="privilege,openbmc,"
838 + ",".join([dmtf[0] for dmtf in dmtf_registries]),
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600839 help="Comma delimited list of registries to update",
840 )
Nan Zhou49aa131f2022-09-20 18:41:37 +0000841
842 args = parser.parse_args()
843
844 registries = set(args.registries.split(","))
845 files = []
846
Gunnar Mills665e7602024-04-10 13:14:41 -0500847 for registry, version in dmtf_registries:
848 if registry in registries:
849 registry_pascal_case = to_pascal_case(registry)
850 files.append(
851 make_getter(
852 f"{registry_pascal_case}.{version}.json",
853 f"{registry}_message_registry.hpp",
854 registry,
855 )
Patrick Williamsdfa3fdc2022-12-07 07:14:21 -0600856 )
Ed Tanous3e5faba2023-08-16 15:11:29 -0700857 if "openbmc" in registries:
858 files.append(openbmc_local_getter())
Nan Zhou49aa131f2022-09-20 18:41:37 +0000859
860 update_registries(files)
861
Ed Tanous42079ec2024-11-16 13:32:29 -0800862 create_error_registry(files[0])
863
Nan Zhou49aa131f2022-09-20 18:41:37 +0000864 if "privilege" in registries:
865 make_privilege_registry()
866
867
868if __name__ == "__main__":
869 main()