blob: 0fd40eff3716c599200afe919f0e82ee5f7bcb89 [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 Venture298930a2019-07-03 11:44:52 -070021#include "prepare_systemd.hpp"
22#include "update_systemd.hpp"
Patrick Venture298930a2019-07-03 11:44:52 -070023
Patrick Venturea6b4abd2019-07-19 10:58:55 -070024#include <algorithm>
Patrick Venture298930a2019-07-03 11:44:52 -070025#include <cstdio>
26#include <exception>
Patrick Venturea6b4abd2019-07-19 10:58:55 -070027#include <fstream>
Patrick Venture298930a2019-07-03 11:44:52 -070028#include <nlohmann/json.hpp>
Patrick Venturea6b4abd2019-07-19 10:58:55 -070029#include <phosphor-logging/log.hpp>
Patrick Venture298930a2019-07-03 11:44:52 -070030#include <sdbusplus/bus.hpp>
31#include <string>
32#include <vector>
33
34namespace ipmi_flash
35{
36
37std::vector<HandlerConfig> buildHandlerFromJson(const nlohmann::json& data)
38{
39 std::vector<HandlerConfig> handlers;
40
41 for (const auto& item : data)
42 {
43 try
44 {
45 HandlerConfig output;
46
47 /* at() throws an exception when the key is not present. */
48 item.at("blob").get_to(output.blobId);
49
50 /* handler is required. */
51 const auto& h = item.at("handler");
52 const std::string handlerType = h.at("type");
53 if (handlerType == "file")
54 {
55 const auto& path = h.at("path");
56 output.handler = std::make_unique<FileHandler>(path);
57 }
58 else
59 {
60 throw std::runtime_error("Invalid handler type: " +
61 handlerType);
62 }
63
64 /* actions are required (presently). */
65 const auto& a = item.at("actions");
66 std::unique_ptr<ActionPack> pack = std::make_unique<ActionPack>();
67
68 /* It hasn't been fully determined if any action being optional is
69 * useful, so for now they will be required.
70 * TODO: Evaluate how the behaviors change if some actions are
71 * missing, does the code just assume it was successful? I would
72 * think not.
73 */
74 const auto& prep = a.at("preparation");
75 const std::string prepareType = prep.at("type");
76 if (prepareType == "systemd")
77 {
78 const auto& unit = prep.at("unit");
79 pack->preparation = SystemdPreparation::CreatePreparation(
80 sdbusplus::bus::new_default(), unit);
81 }
82 else
83 {
84 throw std::runtime_error("Invalid preparation type: " +
85 prepareType);
86 }
87
88 const auto& verify = a.at("verification");
89 const std::string verifyType = verify.at("type");
90 if (verifyType == "fileSystemdVerify")
91 {
92 const auto& path = verify.at("path");
93 const auto& unit = verify.at("unit");
Patrick Venture984d94d2019-08-05 12:23:59 -070094
95 /* the mode parameter is optional. */
96 std::string systemdMode = "replace";
97 const auto& mode = verify.find("mode");
98 if (mode != verify.end())
99 {
100 systemdMode = verify.at("mode").get<std::string>();
101 }
102
Patrick Venturecf066ac2019-08-06 09:03:47 -0700103 pack->verification =
104 SystemdWithStatusFile::CreateSystemdWithStatusFile(
105 sdbusplus::bus::new_default(), path, unit, systemdMode);
Patrick Venture298930a2019-07-03 11:44:52 -0700106 }
107 else
108 {
109 throw std::runtime_error("Invalid verification type:" +
110 verifyType);
111 }
112
113 const auto& update = a.at("update");
114 const std::string updateType = update.at("type");
115 if (updateType == "reboot")
116 {
117 static constexpr auto rebootTarget = "reboot.target";
118 static constexpr auto rebootMode = "replace-irreversibly";
119 pack->update = SystemdUpdateMechanism::CreateSystemdUpdate(
120 sdbusplus::bus::new_default(), rebootTarget, rebootMode);
121 }
Patrick Venturec2baac92019-08-05 13:30:38 -0700122 else if (updateType == "fileSystemdUpdate")
123 {
124 const auto& path = update.at("path");
125 const auto& unit = update.at("unit");
126
127 /* the mode parameter is optional. */
128 std::string systemdMode = "replace";
129 const auto& mode = update.find("mode");
130 if (mode != update.end())
131 {
132 systemdMode = update.at("mode").get<std::string>();
133 }
134
Patrick Venturecf066ac2019-08-06 09:03:47 -0700135 pack->update =
136 SystemdWithStatusFile::CreateSystemdWithStatusFile(
137 sdbusplus::bus::new_default(), path, unit, systemdMode);
Patrick Venturec2baac92019-08-05 13:30:38 -0700138 }
Patrick Venture298930a2019-07-03 11:44:52 -0700139 else if (updateType == "systemd")
140 {
141 const auto& unit = update.at("unit");
Patrick Venture0caec992019-08-05 09:58:27 -0700142
143 /* the mode parameter is optional. */
144 std::string systemdMode = "replace";
145 const auto& mode = update.find("mode");
146 if (mode != update.end())
147 {
148 systemdMode = update.at("mode").get<std::string>();
149 }
150
Patrick Venture298930a2019-07-03 11:44:52 -0700151 pack->update = SystemdUpdateMechanism::CreateSystemdUpdate(
Patrick Venture0caec992019-08-05 09:58:27 -0700152 sdbusplus::bus::new_default(), unit, systemdMode);
Patrick Venture298930a2019-07-03 11:44:52 -0700153 }
154 else
155 {
156 throw std::runtime_error("Invalid update type: " + updateType);
157 }
158
159 output.actions = std::move(pack);
160 handlers.push_back(std::move(output));
161 }
162 catch (const std::exception& e)
163 {
164 /* TODO: Once phosphor-logging supports unit-test injection, fix
165 * this to log.
166 */
167 std::fprintf(stderr,
168 "Excepted building HandlerConfig from json: %s\n",
169 e.what());
170 }
171 }
172
173 return handlers;
174}
175
Patrick Venturea6b4abd2019-07-19 10:58:55 -0700176std::vector<HandlerConfig> BuildHandlerConfigs(const std::string& directory)
177{
178 using namespace phosphor::logging;
179
180 std::vector<HandlerConfig> output;
181
182 std::vector<std::string> jsonPaths = GetJsonList(directory);
183
184 for (const auto& path : jsonPaths)
185 {
186 std::ifstream jsonFile(path);
187 if (!jsonFile.is_open())
188 {
189 log<level::ERR>("Unable to open json file",
190 entry("PATH=%s", path.c_str()));
191 continue;
192 }
193
194 auto data = nlohmann::json::parse(jsonFile, nullptr, false);
195 if (data.is_discarded())
196 {
197 log<level::ERR>("Parsing json failed",
198 entry("PATH=%s", path.c_str()));
199 continue;
200 }
201
202 std::vector<HandlerConfig> configs = buildHandlerFromJson(data);
203 std::move(configs.begin(), configs.end(), std::back_inserter(output));
204 }
205
206 return output;
207}
208
Patrick Venture298930a2019-07-03 11:44:52 -0700209} // namespace ipmi_flash