xref: /openbmc/bmcweb/redfish-core/src/error_message_utils.cpp (revision 76c2ad64440e2864a0cc3d66a3b8bb0f5ac2f288)
1 #include "error_message_utils.hpp"
2 
3 #include "logging.hpp"
4 
5 #include <nlohmann/json.hpp>
6 
7 #include <string>
8 #include <string_view>
9 #include <utility>
10 
11 namespace redfish
12 {
13 
14 namespace messages
15 {
16 
addMessageToErrorJson(nlohmann::json & target,const nlohmann::json & message)17 void addMessageToErrorJson(nlohmann::json& target,
18                            const nlohmann::json& message)
19 {
20     nlohmann::json::object_t* targetObj =
21         target.get_ptr<nlohmann::json::object_t*>();
22     if (targetObj == nullptr)
23     {
24         target = nlohmann::json::object_t();
25         targetObj = target.get_ptr<nlohmann::json::object_t*>();
26     }
27 
28     nlohmann::json& error = (*targetObj)["error"];
29     nlohmann::json::object_t* errorObj =
30         error.get_ptr<nlohmann::json::object_t*>();
31 
32     // If this is the first error message, fill in the information from the
33     // first error message to the top level struct
34     if (errorObj == nullptr)
35     {
36         auto messageIdIterator = message.find("MessageId");
37         if (messageIdIterator == message.end())
38         {
39             BMCWEB_LOG_CRITICAL(
40                 "Attempt to add error message without MessageId");
41             return;
42         }
43 
44         auto messageFieldIterator = message.find("Message");
45         if (messageFieldIterator == message.end())
46         {
47             BMCWEB_LOG_CRITICAL("Attempt to add error message without Message");
48             return;
49         }
50         nlohmann::json::object_t errorMsg;
51         errorMsg["code"] = *messageIdIterator;
52         errorMsg["message"] = *messageFieldIterator;
53         error = std::move(errorMsg);
54         errorObj = error.get_ptr<nlohmann::json::object_t*>();
55     }
56     else
57     {
58         // More than 1 error occurred, so the message has to be generic
59         (*errorObj)["code"] =
60             std::string(messageVersionPrefix) + "GeneralError";
61         (*errorObj)["message"] =
62             "A general error has occurred. See Resolution for "
63             "information on how to resolve the error.";
64     }
65 
66     // This check could technically be done in the default construction
67     // branch above, but because we need the pointer to the extended info field
68     // anyway, it's more efficient to do it here.
69     auto extendedInfo = errorObj->try_emplace(messages::messageAnnotation,
70                                               nlohmann::json::array());
71 
72     extendedInfo.first->second.push_back(message);
73 }
74 
moveErrorsToErrorJson(nlohmann::json & target,nlohmann::json & source)75 void moveErrorsToErrorJson(nlohmann::json& target, nlohmann::json& source)
76 {
77     nlohmann::json::object_t* sourceObj =
78         source.get_ptr<nlohmann::json::object_t*>();
79     if (sourceObj == nullptr)
80     {
81         return;
82     }
83 
84     nlohmann::json::object_t::iterator errorIt = sourceObj->find("error");
85     if (errorIt == sourceObj->end())
86     {
87         // caller puts error message in root
88         messages::addMessageToErrorJson(target, source);
89         source.clear();
90         return;
91     }
92     nlohmann::json::object_t* errorObj =
93         errorIt->second.get_ptr<nlohmann::json::object_t*>();
94     if (errorObj == nullptr)
95     {
96         return;
97     }
98 
99     nlohmann::json::object_t::iterator extendedInfoIt =
100         errorObj->find(messages::messageAnnotation);
101     if (extendedInfoIt == errorObj->end())
102     {
103         return;
104     }
105     const nlohmann::json::array_t* extendedInfo =
106         extendedInfoIt->second.get_ptr<const nlohmann::json::array_t*>();
107     if (extendedInfo == nullptr)
108     {
109         sourceObj->erase(errorIt);
110         return;
111     }
112     for (const nlohmann::json& message : *extendedInfo)
113     {
114         addMessageToErrorJson(target, message);
115     }
116     sourceObj->erase(errorIt);
117 }
118 
addMessageToJsonRoot(nlohmann::json & target,const nlohmann::json & message)119 void addMessageToJsonRoot(nlohmann::json& target, const nlohmann::json& message)
120 {
121     nlohmann::json& annotation = target[messages::messageAnnotation];
122     if (!annotation.is_array())
123     {
124         // Force object to be an array
125         annotation = nlohmann::json::array();
126     }
127 
128     annotation.push_back(message);
129 }
130 
addMessageToJson(nlohmann::json & target,const nlohmann::json & message,std::string_view fieldPath)131 void addMessageToJson(nlohmann::json& target, const nlohmann::json& message,
132                       std::string_view fieldPath)
133 {
134     std::string extendedInfo(fieldPath);
135     extendedInfo += messages::messageAnnotation;
136 
137     nlohmann::json& field = target[extendedInfo];
138     if (!field.is_array())
139     {
140         // Force object to be an array
141         field = nlohmann::json::array();
142     }
143 
144     // Object exists and it is an array so we can just push in the message
145     field.push_back(message);
146 }
147 
148 } // namespace messages
149 } // namespace redfish
150