blob: 6f9c319b2c0d04a3f524ac420dc8d4932a2fde2e [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
Patrick Venture9cce5a22019-08-06 09:24:46 -070037std::unique_ptr<TriggerableActionInterface>
38 buildFileSystemd(const nlohmann::json& data)
39{
40 /* This type of action requires a path and unit, and optionally a mode. */
41 const auto& path = data.at("path");
42 const auto& unit = data.at("unit");
43
44 /* the mode parameter is optional. */
45 std::string systemdMode = "replace";
46 const auto& mode = data.find("mode");
47 if (mode != data.end())
48 {
49 systemdMode = data.at("mode").get<std::string>();
50 }
51
52 return SystemdWithStatusFile::CreateSystemdWithStatusFile(
53 sdbusplus::bus::new_default(), path, unit, systemdMode);
54}
55
Patrick Venture298930a2019-07-03 11:44:52 -070056std::vector<HandlerConfig> buildHandlerFromJson(const nlohmann::json& data)
57{
58 std::vector<HandlerConfig> handlers;
59
60 for (const auto& item : data)
61 {
62 try
63 {
64 HandlerConfig output;
65
66 /* at() throws an exception when the key is not present. */
67 item.at("blob").get_to(output.blobId);
68
69 /* handler is required. */
70 const auto& h = item.at("handler");
71 const std::string handlerType = h.at("type");
72 if (handlerType == "file")
73 {
74 const auto& path = h.at("path");
75 output.handler = std::make_unique<FileHandler>(path);
76 }
77 else
78 {
79 throw std::runtime_error("Invalid handler type: " +
80 handlerType);
81 }
82
83 /* actions are required (presently). */
84 const auto& a = item.at("actions");
85 std::unique_ptr<ActionPack> pack = std::make_unique<ActionPack>();
86
87 /* It hasn't been fully determined if any action being optional is
88 * useful, so for now they will be required.
89 * TODO: Evaluate how the behaviors change if some actions are
90 * missing, does the code just assume it was successful? I would
91 * think not.
92 */
93 const auto& prep = a.at("preparation");
94 const std::string prepareType = prep.at("type");
95 if (prepareType == "systemd")
96 {
97 const auto& unit = prep.at("unit");
98 pack->preparation = SystemdPreparation::CreatePreparation(
99 sdbusplus::bus::new_default(), unit);
100 }
101 else
102 {
103 throw std::runtime_error("Invalid preparation type: " +
104 prepareType);
105 }
106
107 const auto& verify = a.at("verification");
108 const std::string verifyType = verify.at("type");
109 if (verifyType == "fileSystemdVerify")
110 {
Patrick Venture9cce5a22019-08-06 09:24:46 -0700111 pack->verification = std::move(buildFileSystemd(verify));
Patrick Venture298930a2019-07-03 11:44:52 -0700112 }
113 else
114 {
115 throw std::runtime_error("Invalid verification type:" +
116 verifyType);
117 }
118
119 const auto& update = a.at("update");
120 const std::string updateType = update.at("type");
121 if (updateType == "reboot")
122 {
123 static constexpr auto rebootTarget = "reboot.target";
124 static constexpr auto rebootMode = "replace-irreversibly";
125 pack->update = SystemdUpdateMechanism::CreateSystemdUpdate(
126 sdbusplus::bus::new_default(), rebootTarget, rebootMode);
127 }
Patrick Venturec2baac92019-08-05 13:30:38 -0700128 else if (updateType == "fileSystemdUpdate")
129 {
Patrick Venture9cce5a22019-08-06 09:24:46 -0700130 pack->update = std::move(buildFileSystemd(update));
Patrick Venturec2baac92019-08-05 13:30:38 -0700131 }
Patrick Venture298930a2019-07-03 11:44:52 -0700132 else if (updateType == "systemd")
133 {
134 const auto& unit = update.at("unit");
Patrick Venture0caec992019-08-05 09:58:27 -0700135
136 /* the mode parameter is optional. */
137 std::string systemdMode = "replace";
138 const auto& mode = update.find("mode");
139 if (mode != update.end())
140 {
141 systemdMode = update.at("mode").get<std::string>();
142 }
143
Patrick Venture298930a2019-07-03 11:44:52 -0700144 pack->update = SystemdUpdateMechanism::CreateSystemdUpdate(
Patrick Venture0caec992019-08-05 09:58:27 -0700145 sdbusplus::bus::new_default(), unit, systemdMode);
Patrick Venture298930a2019-07-03 11:44:52 -0700146 }
147 else
148 {
149 throw std::runtime_error("Invalid update type: " + updateType);
150 }
151
152 output.actions = std::move(pack);
153 handlers.push_back(std::move(output));
154 }
155 catch (const std::exception& e)
156 {
157 /* TODO: Once phosphor-logging supports unit-test injection, fix
158 * this to log.
159 */
160 std::fprintf(stderr,
161 "Excepted building HandlerConfig from json: %s\n",
162 e.what());
163 }
164 }
165
166 return handlers;
167}
168
Patrick Venturea6b4abd2019-07-19 10:58:55 -0700169std::vector<HandlerConfig> BuildHandlerConfigs(const std::string& directory)
170{
171 using namespace phosphor::logging;
172
173 std::vector<HandlerConfig> output;
174
175 std::vector<std::string> jsonPaths = GetJsonList(directory);
176
177 for (const auto& path : jsonPaths)
178 {
179 std::ifstream jsonFile(path);
180 if (!jsonFile.is_open())
181 {
182 log<level::ERR>("Unable to open json file",
183 entry("PATH=%s", path.c_str()));
184 continue;
185 }
186
187 auto data = nlohmann::json::parse(jsonFile, nullptr, false);
188 if (data.is_discarded())
189 {
190 log<level::ERR>("Parsing json failed",
191 entry("PATH=%s", path.c_str()));
192 continue;
193 }
194
195 std::vector<HandlerConfig> configs = buildHandlerFromJson(data);
196 std::move(configs.begin(), configs.end(), std::back_inserter(output));
197 }
198
199 return output;
200}
201
Patrick Venture298930a2019-07-03 11:44:52 -0700202} // namespace ipmi_flash