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