blob: 822e640e0a365a8954016e022f998153e37bcef8 [file] [log] [blame]
Patrick Venture298930a2019-07-03 11:44:52 -07001/*
2 * Copyright 2019 Google Inc.
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#include "buildjson.hpp"
17
18#include "file_handler.hpp"
Patrick Venturea6b4abd2019-07-19 10:58:55 -070019#include "fs.hpp"
Patrick Venturecf066ac2019-08-06 09:03:47 -070020#include "general_systemd.hpp"
Patrick Ventured53d60a2020-04-07 09:01:34 -070021#include "skip_action.hpp"
Patrick Venture298930a2019-07-03 11:44:52 -070022
Patrick Venture9b37b092020-05-28 20:58:57 -070023#include <nlohmann/json.hpp>
24#include <phosphor-logging/log.hpp>
25#include <sdbusplus/bus.hpp>
26
Patrick Venturea6b4abd2019-07-19 10:58:55 -070027#include <algorithm>
Patrick Venture298930a2019-07-03 11:44:52 -070028#include <cstdio>
29#include <exception>
Patrick Venturea6b4abd2019-07-19 10:58:55 -070030#include <fstream>
Patrick Venture097435f2019-08-15 07:39:48 -070031#include <regex>
Patrick Venture298930a2019-07-03 11:44:52 -070032#include <string>
33#include <vector>
34
35namespace ipmi_flash
36{
37
Patrick Venture9cce5a22019-08-06 09:24:46 -070038std::unique_ptr<TriggerableActionInterface>
39 buildFileSystemd(const nlohmann::json& data)
40{
41 /* This type of action requires a path and unit, and optionally a mode. */
42 const auto& path = data.at("path");
43 const auto& unit = data.at("unit");
44
45 /* the mode parameter is optional. */
46 std::string systemdMode = "replace";
47 const auto& mode = data.find("mode");
48 if (mode != data.end())
49 {
50 systemdMode = data.at("mode").get<std::string>();
51 }
52
53 return SystemdWithStatusFile::CreateSystemdWithStatusFile(
54 sdbusplus::bus::new_default(), path, unit, systemdMode);
55}
56
Patrick Venturee0216d22019-08-21 10:17:39 -070057std::unique_ptr<TriggerableActionInterface>
58 buildSystemd(const nlohmann::json& data)
59{
60 /* This type of action requires a unit, and optionally a mode. */
61 const auto& unit = data.at("unit");
62
63 /* the mode parameter is optional. */
64 std::string systemdMode = "replace";
65 const auto& mode = data.find("mode");
66 if (mode != data.end())
67 {
68 systemdMode = data.at("mode").get<std::string>();
69 }
70
71 return SystemdNoFile::CreateSystemdNoFile(sdbusplus::bus::new_default(),
72 unit, systemdMode);
73}
74
Patrick Venture298930a2019-07-03 11:44:52 -070075std::vector<HandlerConfig> buildHandlerFromJson(const nlohmann::json& data)
76{
77 std::vector<HandlerConfig> handlers;
78
79 for (const auto& item : data)
80 {
81 try
82 {
83 HandlerConfig output;
84
85 /* at() throws an exception when the key is not present. */
86 item.at("blob").get_to(output.blobId);
87
Patrick Venture097435f2019-08-15 07:39:48 -070088 /* name must be: /flash/... */
89 if (!std::regex_match(output.blobId, std::regex("^\\/flash\\/.+")))
90 {
91 throw std::runtime_error("Invalid blob name: '" +
92 output.blobId +
93 "' must start with /flash/");
94 }
95
Patrick Venture298930a2019-07-03 11:44:52 -070096 /* handler is required. */
97 const auto& h = item.at("handler");
98 const std::string handlerType = h.at("type");
99 if (handlerType == "file")
100 {
101 const auto& path = h.at("path");
102 output.handler = std::make_unique<FileHandler>(path);
103 }
104 else
105 {
106 throw std::runtime_error("Invalid handler type: " +
107 handlerType);
108 }
109
110 /* actions are required (presently). */
111 const auto& a = item.at("actions");
112 std::unique_ptr<ActionPack> pack = std::make_unique<ActionPack>();
113
Patrick Ventured53d60a2020-04-07 09:01:34 -0700114 /* to make an action optional, assign type "skip" */
Patrick Venture298930a2019-07-03 11:44:52 -0700115 const auto& prep = a.at("preparation");
116 const std::string prepareType = prep.at("type");
117 if (prepareType == "systemd")
118 {
Patrick Venturee0216d22019-08-21 10:17:39 -0700119 pack->preparation = std::move(buildSystemd(prep));
Patrick Venture298930a2019-07-03 11:44:52 -0700120 }
Patrick Ventured53d60a2020-04-07 09:01:34 -0700121 else if (prepareType == "skip")
122 {
123 pack->preparation = SkipAction::CreateSkipAction();
124 }
Patrick Venture298930a2019-07-03 11:44:52 -0700125 else
126 {
127 throw std::runtime_error("Invalid preparation type: " +
128 prepareType);
129 }
130
131 const auto& verify = a.at("verification");
132 const std::string verifyType = verify.at("type");
133 if (verifyType == "fileSystemdVerify")
134 {
Patrick Venture9cce5a22019-08-06 09:24:46 -0700135 pack->verification = std::move(buildFileSystemd(verify));
Patrick Venture298930a2019-07-03 11:44:52 -0700136 }
William A. Kennington III2d434c82019-11-22 18:42:35 -0800137 else if (verifyType == "systemd")
138 {
139 pack->verification = std::move(buildSystemd(verify));
140 }
Patrick Ventured53d60a2020-04-07 09:01:34 -0700141 else if (verifyType == "skip")
142 {
143 pack->verification = SkipAction::CreateSkipAction();
144 }
Patrick Venture298930a2019-07-03 11:44:52 -0700145 else
146 {
147 throw std::runtime_error("Invalid verification type:" +
148 verifyType);
149 }
150
151 const auto& update = a.at("update");
152 const std::string updateType = update.at("type");
153 if (updateType == "reboot")
154 {
Patrick Venturee0216d22019-08-21 10:17:39 -0700155 pack->update = SystemdNoFile::CreateSystemdNoFile(
Patrick Venture44564902019-08-21 09:46:32 -0700156 sdbusplus::bus::new_default(), "reboot.target",
157 "replace-irreversibly");
Patrick Venture298930a2019-07-03 11:44:52 -0700158 }
Patrick Venturec2baac92019-08-05 13:30:38 -0700159 else if (updateType == "fileSystemdUpdate")
160 {
Patrick Venture9cce5a22019-08-06 09:24:46 -0700161 pack->update = std::move(buildFileSystemd(update));
Patrick Venturec2baac92019-08-05 13:30:38 -0700162 }
Patrick Venture298930a2019-07-03 11:44:52 -0700163 else if (updateType == "systemd")
164 {
Patrick Venturee0216d22019-08-21 10:17:39 -0700165 pack->update = std::move(buildSystemd(update));
Patrick Venture298930a2019-07-03 11:44:52 -0700166 }
Patrick Ventured53d60a2020-04-07 09:01:34 -0700167 else if (updateType == "skip")
168 {
169 pack->update = SkipAction::CreateSkipAction();
170 }
Patrick Venture298930a2019-07-03 11:44:52 -0700171 else
172 {
173 throw std::runtime_error("Invalid update type: " + updateType);
174 }
175
176 output.actions = std::move(pack);
177 handlers.push_back(std::move(output));
178 }
179 catch (const std::exception& e)
180 {
181 /* TODO: Once phosphor-logging supports unit-test injection, fix
182 * this to log.
183 */
184 std::fprintf(stderr,
185 "Excepted building HandlerConfig from json: %s\n",
186 e.what());
187 }
188 }
189
190 return handlers;
191}
192
Patrick Venturea6b4abd2019-07-19 10:58:55 -0700193std::vector<HandlerConfig> BuildHandlerConfigs(const std::string& directory)
194{
195 using namespace phosphor::logging;
196
197 std::vector<HandlerConfig> output;
198
199 std::vector<std::string> jsonPaths = GetJsonList(directory);
200
201 for (const auto& path : jsonPaths)
202 {
203 std::ifstream jsonFile(path);
204 if (!jsonFile.is_open())
205 {
206 log<level::ERR>("Unable to open json file",
207 entry("PATH=%s", path.c_str()));
208 continue;
209 }
210
211 auto data = nlohmann::json::parse(jsonFile, nullptr, false);
212 if (data.is_discarded())
213 {
214 log<level::ERR>("Parsing json failed",
215 entry("PATH=%s", path.c_str()));
216 continue;
217 }
218
219 std::vector<HandlerConfig> configs = buildHandlerFromJson(data);
220 std::move(configs.begin(), configs.end(), std::back_inserter(output));
221 }
222
223 return output;
224}
225
Patrick Venture298930a2019-07-03 11:44:52 -0700226} // namespace ipmi_flash