blob: f91d5f843e93d0308d60e39819787c983d271198 [file] [log] [blame]
Matt Spinleracb7c102020-01-10 13:49:22 -06001/**
2 * Copyright © 2020 IBM Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "user_data_json.hpp"
18
Harisuddin Mohamed Isabebeb942020-03-12 17:12:24 +080019#include "json_utils.hpp"
Matt Spinleracb7c102020-01-10 13:49:22 -060020#include "pel_types.hpp"
Harisuddin Mohamed Isabebeb942020-03-12 17:12:24 +080021#include "pel_values.hpp"
Matt Spinleracb7c102020-01-10 13:49:22 -060022#include "user_data_formats.hpp"
23
24#include <fifo_map.hpp>
25#include <iomanip>
26#include <nlohmann/json.hpp>
27#include <phosphor-logging/log.hpp>
28#include <sstream>
29
30namespace openpower::pels::user_data
31{
Harisuddin Mohamed Isabebeb942020-03-12 17:12:24 +080032namespace pv = openpower::pels::pel_values;
Matt Spinleracb7c102020-01-10 13:49:22 -060033using namespace phosphor::logging;
34
35// Use fifo_map as nlohmann::json's map. We are just ignoring the 'less'
36// compare. With this map the keys are kept in FIFO order.
37template <class K, class V, class dummy_compare, class A>
38using fifoMap = nlohmann::fifo_map<K, V, nlohmann::fifo_map_compare<K>, A>;
39using fifoJSON = nlohmann::basic_json<fifoMap>;
40
41/**
42 * @brief Returns a JSON string for use by PEL::printSectionInJSON().
43 *
44 * The returning string will contain a JSON object, but without
45 * the outer {}. If the input JSON isn't a JSON object (dict), then
46 * one will be created with the input added to a 'Data' key.
47 *
48 * @param[in] json - The JSON to convert to a string
49 *
50 * @return std::string - The JSON string
51 */
52std::string prettyJSON(uint16_t componentID, uint8_t subType, uint8_t version,
53 const fifoJSON& json)
54{
55 fifoJSON output;
Harisuddin Mohamed Isabebeb942020-03-12 17:12:24 +080056 output[pv::sectionVer] = std::to_string(version);
57 output[pv::subSection] = std::to_string(subType);
58 output[pv::createdBy] = getNumberString("0x%04X", componentID);
Matt Spinleracb7c102020-01-10 13:49:22 -060059
60 if (!json.is_object())
61 {
62 output["Data"] = json;
63 }
64 else
65 {
66 for (const auto& [key, value] : json.items())
67 {
68 output[key] = value;
69 }
70 }
71
72 // Let nlohmann do the pretty printing.
73 std::stringstream stream;
74 stream << std::setw(4) << output;
75
76 auto jsonString = stream.str();
77
78 // Now it looks like:
79 // {
80 // "Section Version": ...
81 // ...
82 // }
83
84 // Since PEL::printSectionInJSON() will supply the outer { }s,
85 // remove the existing ones.
86
87 // Replace the { and the following newline, and the } and its
88 // preceeding newline.
89 jsonString.erase(0, 2);
90
91 auto pos = jsonString.find_last_of('}');
92 jsonString.erase(pos - 1);
93
94 return jsonString;
95}
96
97/**
98 * @brief Convert to an appropriate JSON string as the data is one of
99 * the formats that we natively support.
100 *
101 * @param[in] componentID - The comp ID from the UserData section header
102 * @param[in] subType - The subtype from the UserData section header
103 * @param[in] version - The version from the UserData section header
104 * @param[in] data - The data itself
105 *
106 * @return std::optional<std::string> - The JSON string if it could be created,
107 * else std::nullopt.
108 */
109std::optional<std::string>
110 getBuiltinFormatJSON(uint16_t componentID, uint8_t subType, uint8_t version,
111 const std::vector<uint8_t>& data)
112{
113 switch (subType)
114 {
115 case static_cast<uint8_t>(UserDataFormat::json):
116 {
117 std::string jsonString{data.begin(), data.begin() + data.size()};
118
119 fifoJSON json = nlohmann::json::parse(jsonString);
120
121 return prettyJSON(componentID, subType, version, json);
122 }
123 default:
124 break;
125 }
126 return std::nullopt;
127}
128
129std::optional<std::string> getJSON(uint16_t componentID, uint8_t subType,
130 uint8_t version,
131 const std::vector<uint8_t>& data)
132{
133 try
134 {
135 switch (componentID)
136 {
137 case static_cast<uint16_t>(ComponentID::phosphorLogging):
138 return getBuiltinFormatJSON(componentID, subType, version,
139 data);
140 default:
141 break;
142 }
143 }
144 catch (std::exception& e)
145 {
146 log<level::ERR>("Failed parsing UserData", entry("ERROR=%s", e.what()));
147 }
148
149 return std::nullopt;
150}
151
152} // namespace openpower::pels::user_data