xref: /openbmc/phosphor-ipmi-flash/bmc/firmware-handler/firmware_handlers_builder.cpp (revision c893f43d5f8a3c0b05c0f6f67d1b232a8117cf71)
1*c893f43dSJason Ling /*
2*c893f43dSJason Ling  * Copyright 2019 Google Inc.
3*c893f43dSJason Ling  *
4*c893f43dSJason Ling  * Licensed under the Apache License, Version 2.0 (the "License");
5*c893f43dSJason Ling  * you may not use this file except in compliance with the License.
6*c893f43dSJason Ling  * You may obtain a copy of the License at
7*c893f43dSJason Ling  *
8*c893f43dSJason Ling  *     http://www.apache.org/licenses/LICENSE-2.0
9*c893f43dSJason Ling  *
10*c893f43dSJason Ling  * Unless required by applicable law or agreed to in writing, software
11*c893f43dSJason Ling  * distributed under the License is distributed on an "AS IS" BASIS,
12*c893f43dSJason Ling  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*c893f43dSJason Ling  * See the License for the specific language governing permissions and
14*c893f43dSJason Ling  * limitations under the License.
15*c893f43dSJason Ling  */
16*c893f43dSJason Ling #include "firmware_handlers_builder.hpp"
17*c893f43dSJason Ling 
18*c893f43dSJason Ling #include "file_handler.hpp"
19*c893f43dSJason Ling #include "fs.hpp"
20*c893f43dSJason Ling #include "skip_action.hpp"
21*c893f43dSJason Ling 
22*c893f43dSJason Ling #include <nlohmann/json.hpp>
23*c893f43dSJason Ling 
24*c893f43dSJason Ling #include <algorithm>
25*c893f43dSJason Ling #include <cstdio>
26*c893f43dSJason Ling #include <exception>
27*c893f43dSJason Ling #include <fstream>
28*c893f43dSJason Ling #include <regex>
29*c893f43dSJason Ling #include <string>
30*c893f43dSJason Ling #include <vector>
31*c893f43dSJason Ling 
32*c893f43dSJason Ling namespace ipmi_flash
33*c893f43dSJason Ling {
34*c893f43dSJason Ling std::vector<HandlerConfig<ActionPack>>
35*c893f43dSJason Ling     FirmwareHandlersBuilder::buildHandlerFromJson(const nlohmann::json& data)
36*c893f43dSJason Ling {
37*c893f43dSJason Ling     std::vector<HandlerConfig<ActionPack>> handlers;
38*c893f43dSJason Ling 
39*c893f43dSJason Ling     for (const auto& item : data)
40*c893f43dSJason Ling     {
41*c893f43dSJason Ling         try
42*c893f43dSJason Ling         {
43*c893f43dSJason Ling             HandlerConfig<ActionPack> output;
44*c893f43dSJason Ling 
45*c893f43dSJason Ling             /* at() throws an exception when the key is not present. */
46*c893f43dSJason Ling             item.at("blob").get_to(output.blobId);
47*c893f43dSJason Ling 
48*c893f43dSJason Ling             /* name must be: /flash/... */
49*c893f43dSJason Ling             if (!std::regex_match(output.blobId, std::regex("^\\/flash\\/.+")))
50*c893f43dSJason Ling             {
51*c893f43dSJason Ling                 throw std::runtime_error("Invalid blob name: '" +
52*c893f43dSJason Ling                                          output.blobId +
53*c893f43dSJason Ling                                          "' must start with /flash/");
54*c893f43dSJason Ling             }
55*c893f43dSJason Ling 
56*c893f43dSJason Ling             /* handler is required. */
57*c893f43dSJason Ling             const auto& h = item.at("handler");
58*c893f43dSJason Ling             const std::string handlerType = h.at("type");
59*c893f43dSJason Ling             if (handlerType == "file")
60*c893f43dSJason Ling             {
61*c893f43dSJason Ling                 const auto& path = h.at("path");
62*c893f43dSJason Ling                 output.handler = std::make_unique<FileHandler>(path);
63*c893f43dSJason Ling             }
64*c893f43dSJason Ling             else
65*c893f43dSJason Ling             {
66*c893f43dSJason Ling                 throw std::runtime_error("Invalid handler type: " +
67*c893f43dSJason Ling                                          handlerType);
68*c893f43dSJason Ling             }
69*c893f43dSJason Ling 
70*c893f43dSJason Ling             /* actions are required (presently). */
71*c893f43dSJason Ling             const auto& a = item.at("actions");
72*c893f43dSJason Ling             std::unique_ptr<ActionPack> pack = std::make_unique<ActionPack>();
73*c893f43dSJason Ling 
74*c893f43dSJason Ling             /* to make an action optional, assign type "skip" */
75*c893f43dSJason Ling             const auto& prep = a.at("preparation");
76*c893f43dSJason Ling             const std::string prepareType = prep.at("type");
77*c893f43dSJason Ling             if (prepareType == "systemd")
78*c893f43dSJason Ling             {
79*c893f43dSJason Ling                 pack->preparation = std::move(buildSystemd(prep));
80*c893f43dSJason Ling             }
81*c893f43dSJason Ling             else if (prepareType == "skip")
82*c893f43dSJason Ling             {
83*c893f43dSJason Ling                 pack->preparation = SkipAction::CreateSkipAction();
84*c893f43dSJason Ling             }
85*c893f43dSJason Ling             else
86*c893f43dSJason Ling             {
87*c893f43dSJason Ling                 throw std::runtime_error("Invalid preparation type: " +
88*c893f43dSJason Ling                                          prepareType);
89*c893f43dSJason Ling             }
90*c893f43dSJason Ling 
91*c893f43dSJason Ling             const auto& verify = a.at("verification");
92*c893f43dSJason Ling             const std::string verifyType = verify.at("type");
93*c893f43dSJason Ling             if (verifyType == "fileSystemdVerify")
94*c893f43dSJason Ling             {
95*c893f43dSJason Ling                 pack->verification = std::move(buildFileSystemd(verify));
96*c893f43dSJason Ling             }
97*c893f43dSJason Ling             else if (verifyType == "systemd")
98*c893f43dSJason Ling             {
99*c893f43dSJason Ling                 pack->verification = std::move(buildSystemd(verify));
100*c893f43dSJason Ling             }
101*c893f43dSJason Ling             else if (verifyType == "skip")
102*c893f43dSJason Ling             {
103*c893f43dSJason Ling                 pack->verification = SkipAction::CreateSkipAction();
104*c893f43dSJason Ling             }
105*c893f43dSJason Ling             else
106*c893f43dSJason Ling             {
107*c893f43dSJason Ling                 throw std::runtime_error("Invalid verification type:" +
108*c893f43dSJason Ling                                          verifyType);
109*c893f43dSJason Ling             }
110*c893f43dSJason Ling 
111*c893f43dSJason Ling             const auto& update = a.at("update");
112*c893f43dSJason Ling             const std::string updateType = update.at("type");
113*c893f43dSJason Ling             if (updateType == "reboot")
114*c893f43dSJason Ling             {
115*c893f43dSJason Ling                 pack->update = SystemdNoFile::CreateSystemdNoFile(
116*c893f43dSJason Ling                     sdbusplus::bus::new_default(), "reboot.target",
117*c893f43dSJason Ling                     "replace-irreversibly");
118*c893f43dSJason Ling             }
119*c893f43dSJason Ling             else if (updateType == "fileSystemdUpdate")
120*c893f43dSJason Ling             {
121*c893f43dSJason Ling                 pack->update = std::move(buildFileSystemd(update));
122*c893f43dSJason Ling             }
123*c893f43dSJason Ling             else if (updateType == "systemd")
124*c893f43dSJason Ling             {
125*c893f43dSJason Ling                 pack->update = std::move(buildSystemd(update));
126*c893f43dSJason Ling             }
127*c893f43dSJason Ling             else if (updateType == "skip")
128*c893f43dSJason Ling             {
129*c893f43dSJason Ling                 pack->update = SkipAction::CreateSkipAction();
130*c893f43dSJason Ling             }
131*c893f43dSJason Ling             else
132*c893f43dSJason Ling             {
133*c893f43dSJason Ling                 throw std::runtime_error("Invalid update type: " + updateType);
134*c893f43dSJason Ling             }
135*c893f43dSJason Ling 
136*c893f43dSJason Ling             output.actions = std::move(pack);
137*c893f43dSJason Ling             handlers.push_back(std::move(output));
138*c893f43dSJason Ling         }
139*c893f43dSJason Ling         catch (const std::exception& e)
140*c893f43dSJason Ling         {
141*c893f43dSJason Ling             /* TODO: Once phosphor-logging supports unit-test injection, fix
142*c893f43dSJason Ling              * this to log.
143*c893f43dSJason Ling              */
144*c893f43dSJason Ling             std::fprintf(stderr,
145*c893f43dSJason Ling                          "Excepted building HandlerConfig from json: %s\n",
146*c893f43dSJason Ling                          e.what());
147*c893f43dSJason Ling         }
148*c893f43dSJason Ling     }
149*c893f43dSJason Ling 
150*c893f43dSJason Ling     return handlers;
151*c893f43dSJason Ling }
152*c893f43dSJason Ling } // namespace ipmi_flash
153