blob: d9a502fa47fe5e6a870f78e4924d04d5debd654d [file] [log] [blame]
Lei YU01539e72019-07-31 10:57:38 +08001#include "config.h"
2
3#include "item_updater.hpp"
4
Lei YUad90ad52019-08-06 11:19:28 +08005#include "utils.hpp"
6
Lei YU01539e72019-07-31 10:57:38 +08007#include <filesystem>
8#include <phosphor-logging/elog-errors.hpp>
9#include <phosphor-logging/log.hpp>
10#include <xyz/openbmc_project/Common/error.hpp>
11
Lei YUfda15a32019-09-19 14:43:02 +080012namespace
13{
14constexpr auto EXTENDED_VERSION = "extended_version";
15}
16
Lei YU01539e72019-07-31 10:57:38 +080017namespace phosphor
18{
19namespace software
20{
21namespace updater
22{
23namespace server = sdbusplus::xyz::openbmc_project::Software::server;
24namespace fs = std::filesystem;
25
26using namespace sdbusplus::xyz::openbmc_project::Common::Error;
27using namespace phosphor::logging;
Lei YUad90ad52019-08-06 11:19:28 +080028using SVersion = server::Version;
29using VersionPurpose = SVersion::VersionPurpose;
Lei YU01539e72019-07-31 10:57:38 +080030
31void ItemUpdater::createActivation(sdbusplus::message::message& m)
32{
Lei YU01539e72019-07-31 10:57:38 +080033 namespace msg = sdbusplus::message;
34 namespace variant_ns = msg::variant_ns;
35
36 sdbusplus::message::object_path objPath;
37 std::map<std::string, std::map<std::string, msg::variant<std::string>>>
38 interfaces;
39 m.read(objPath, interfaces);
40
41 std::string path(std::move(objPath));
42 std::string filePath;
43 auto purpose = VersionPurpose::Unknown;
44 std::string version;
45
46 for (const auto& [interfaceName, propertyMap] : interfaces)
47 {
48 if (interfaceName == VERSION_IFACE)
49 {
50 for (const auto& [propertyName, propertyValue] : propertyMap)
51 {
52 if (propertyName == "Purpose")
53 {
54 // Only process the PSU images
55 auto value = SVersion::convertVersionPurposeFromString(
56 variant_ns::get<std::string>(propertyValue));
57
58 if (value == VersionPurpose::PSU)
59 {
60 purpose = value;
61 }
62 }
Lei YUf77189f2019-08-07 14:26:30 +080063 else if (propertyName == VERSION)
Lei YU01539e72019-07-31 10:57:38 +080064 {
65 version = variant_ns::get<std::string>(propertyValue);
66 }
67 }
68 }
69 else if (interfaceName == FILEPATH_IFACE)
70 {
71 const auto& it = propertyMap.find("Path");
72 if (it != propertyMap.end())
73 {
74 filePath = variant_ns::get<std::string>(it->second);
75 }
76 }
77 }
78 if ((filePath.empty()) || (purpose == VersionPurpose::Unknown))
79 {
80 return;
81 }
82
83 // Version id is the last item in the path
84 auto pos = path.rfind("/");
85 if (pos == std::string::npos)
86 {
87 log<level::ERR>("No version id found in object path",
88 entry("OBJPATH=%s", path.c_str()));
89 return;
90 }
91
92 auto versionId = path.substr(pos + 1);
93
94 if (activations.find(versionId) == activations.end())
95 {
96 // Determine the Activation state by processing the given image dir.
Lei YU91029442019-08-01 15:57:31 +080097 AssociationList associations;
Lei YU01539e72019-07-31 10:57:38 +080098 auto activationState = server::Activation::Activations::Ready;
99
Lei YU91029442019-08-01 15:57:31 +0800100 associations.emplace_back(std::make_tuple(ACTIVATION_FWD_ASSOCIATION,
101 ACTIVATION_REV_ASSOCIATION,
Lei YU5e0dcb32019-08-02 18:04:34 +0800102 PSU_INVENTORY_PATH_BASE));
Lei YU91029442019-08-01 15:57:31 +0800103
Lei YU01539e72019-07-31 10:57:38 +0800104 fs::path manifestPath(filePath);
105 manifestPath /= MANIFEST_FILE;
Lei YUfda15a32019-09-19 14:43:02 +0800106 std::string extendedVersion;
107 auto values =
108 Version::getValues(manifestPath.string(), {EXTENDED_VERSION});
109 const auto it = values.find(EXTENDED_VERSION);
110 if (it != values.end())
111 {
112 extendedVersion = it->second;
113 }
Lei YU01539e72019-07-31 10:57:38 +0800114
115 auto activation = createActivationObject(
Lei YU91029442019-08-01 15:57:31 +0800116 path, versionId, extendedVersion, activationState, associations);
Lei YU01539e72019-07-31 10:57:38 +0800117 activations.emplace(versionId, std::move(activation));
118
119 auto versionPtr =
120 createVersionObject(path, versionId, version, purpose, filePath);
121 versions.emplace(versionId, std::move(versionPtr));
122 }
123 return;
124}
125
126void ItemUpdater::erase(std::string versionId)
127{
128 auto it = versions.find(versionId);
129 if (it == versions.end())
130 {
131 log<level::ERR>(("Error: Failed to find version " + versionId +
132 " in item updater versions map."
133 " Unable to remove.")
134 .c_str());
135 }
136 else
137 {
138 versions.erase(versionId);
139 }
140
141 // Removing entry in activations map
142 auto ita = activations.find(versionId);
143 if (ita == activations.end())
144 {
145 log<level::ERR>(("Error: Failed to find version " + versionId +
146 " in item updater activations map."
147 " Unable to remove.")
148 .c_str());
149 }
150 else
151 {
152 activations.erase(versionId);
153 }
154}
155
156void ItemUpdater::deleteAll()
157{
158 // TODO: when PSU's running firmware is implemented, delete all versions
159 // that are not the running firmware.
160}
161
Lei YU91029442019-08-01 15:57:31 +0800162void ItemUpdater::createActiveAssociation(const std::string& path)
163{
164 assocs.emplace_back(
165 std::make_tuple(ACTIVE_FWD_ASSOCIATION, ACTIVE_REV_ASSOCIATION, path));
166 associations(assocs);
167}
168
Lei YUad90ad52019-08-06 11:19:28 +0800169void ItemUpdater::addFunctionalAssociation(const std::string& path)
Lei YU91029442019-08-01 15:57:31 +0800170{
Lei YU91029442019-08-01 15:57:31 +0800171 assocs.emplace_back(std::make_tuple(FUNCTIONAL_FWD_ASSOCIATION,
172 FUNCTIONAL_REV_ASSOCIATION, path));
173 associations(assocs);
174}
175
176void ItemUpdater::removeAssociation(const std::string& path)
177{
178 for (auto iter = assocs.begin(); iter != assocs.end();)
179 {
180 if ((std::get<2>(*iter)).compare(path) == 0)
181 {
182 iter = assocs.erase(iter);
183 associations(assocs);
184 }
185 else
186 {
187 ++iter;
188 }
189 }
190}
191
Lei YU01539e72019-07-31 10:57:38 +0800192std::unique_ptr<Activation> ItemUpdater::createActivationObject(
193 const std::string& path, const std::string& versionId,
194 const std::string& extVersion,
195 sdbusplus::xyz::openbmc_project::Software::server::Activation::Activations
Lei YU91029442019-08-01 15:57:31 +0800196 activationStatus,
197 const AssociationList& assocs)
Lei YU01539e72019-07-31 10:57:38 +0800198{
199 return std::make_unique<Activation>(bus, path, versionId, extVersion,
Lei YU7f2a2152019-09-16 16:50:18 +0800200 activationStatus, assocs, this);
Lei YU01539e72019-07-31 10:57:38 +0800201}
202
Lei YUad90ad52019-08-06 11:19:28 +0800203void ItemUpdater::createPsuObject(const std::string& psuInventoryPath,
204 const std::string& psuVersion)
205{
206 auto versionId = utils::getVersionId(psuVersion);
207 auto path = std::string(SOFTWARE_OBJPATH) + "/" + versionId;
208
209 auto it = activations.find(versionId);
210 if (it != activations.end())
211 {
212 // The versionId is already created, associate the path
213 auto associations = it->second->associations();
214 associations.emplace_back(std::make_tuple(ACTIVATION_FWD_ASSOCIATION,
215 ACTIVATION_REV_ASSOCIATION,
216 psuInventoryPath));
217 it->second->associations(associations);
Lei YUbd3b0072019-08-08 13:09:50 +0800218 psuPathActivationMap.emplace(psuInventoryPath, it->second);
Lei YUad90ad52019-08-06 11:19:28 +0800219 }
220 else
221 {
222 // Create a new object for running PSU inventory
223 AssociationList associations;
224 auto activationState = server::Activation::Activations::Active;
225
226 associations.emplace_back(std::make_tuple(ACTIVATION_FWD_ASSOCIATION,
227 ACTIVATION_REV_ASSOCIATION,
228 psuInventoryPath));
229
230 auto activation = createActivationObject(path, versionId, "",
231 activationState, associations);
232 activations.emplace(versionId, std::move(activation));
Lei YUbd3b0072019-08-08 13:09:50 +0800233 psuPathActivationMap.emplace(psuInventoryPath, activations[versionId]);
Lei YUad90ad52019-08-06 11:19:28 +0800234
235 auto versionPtr = createVersionObject(path, versionId, psuVersion,
236 VersionPurpose::PSU, "");
237 versions.emplace(versionId, std::move(versionPtr));
238
239 createActiveAssociation(path);
240 addFunctionalAssociation(path);
241 }
242}
243
Lei YUbd3b0072019-08-08 13:09:50 +0800244void ItemUpdater::removePsuObject(const std::string& psuInventoryPath)
245{
Lei YUbd3b0072019-08-08 13:09:50 +0800246 auto it = psuPathActivationMap.find(psuInventoryPath);
247 if (it == psuPathActivationMap.end())
248 {
249 log<level::ERR>("No Activation found for PSU",
250 entry("PSUPATH=%s", psuInventoryPath.c_str()));
251 return;
252 }
253 const auto& activationPtr = it->second;
254 psuPathActivationMap.erase(psuInventoryPath);
255
256 auto associations = activationPtr->associations();
257 for (auto iter = associations.begin(); iter != associations.end();)
258 {
259 if ((std::get<2>(*iter)).compare(psuInventoryPath) == 0)
260 {
261 iter = associations.erase(iter);
262 }
263 else
264 {
265 ++iter;
266 }
267 }
268 if (associations.empty())
269 {
270 // Remove the activation
271 erase(activationPtr->versionId);
272 }
273 else
274 {
275 // Update association
276 activationPtr->associations(associations);
277 }
278}
279
Lei YU01539e72019-07-31 10:57:38 +0800280std::unique_ptr<Version> ItemUpdater::createVersionObject(
281 const std::string& objPath, const std::string& versionId,
282 const std::string& versionString,
283 sdbusplus::xyz::openbmc_project::Software::server::Version::VersionPurpose
284 versionPurpose,
285 const std::string& filePath)
286{
287 auto version = std::make_unique<Version>(
288 bus, objPath, versionId, versionString, versionPurpose, filePath,
289 std::bind(&ItemUpdater::erase, this, std::placeholders::_1));
290 return version;
291}
292
Lei YUa2c2cd72019-08-09 15:54:10 +0800293void ItemUpdater::onPsuInventoryChangedMsg(sdbusplus::message::message& msg)
Lei YUad90ad52019-08-06 11:19:28 +0800294{
Lei YUbd3b0072019-08-08 13:09:50 +0800295 using Interface = std::string;
Lei YUbd3b0072019-08-08 13:09:50 +0800296 Interface interface;
297 Properties properties;
Lei YUbd3b0072019-08-08 13:09:50 +0800298 std::string psuPath = msg.get_path();
299
300 msg.read(interface, properties);
Lei YUa2c2cd72019-08-09 15:54:10 +0800301 onPsuInventoryChanged(psuPath, properties);
302}
303
304void ItemUpdater::onPsuInventoryChanged(const std::string& psuPath,
305 const Properties& properties)
306{
Lei YUdcaf8932019-09-09 16:09:35 +0800307 bool present;
308 std::string version;
Lei YUbd3b0072019-08-08 13:09:50 +0800309
Lei YUdcaf8932019-09-09 16:09:35 +0800310 // Only present property is interested
Lei YUf77189f2019-08-07 14:26:30 +0800311 auto p = properties.find(PRESENT);
Lei YUdcaf8932019-09-09 16:09:35 +0800312 if (p == properties.end())
Lei YUbd3b0072019-08-08 13:09:50 +0800313 {
314 return;
315 }
Lei YUdcaf8932019-09-09 16:09:35 +0800316 present = sdbusplus::message::variant_ns::get<bool>(p->second);
Lei YUbd3b0072019-08-08 13:09:50 +0800317
Lei YUdcaf8932019-09-09 16:09:35 +0800318 if (present)
Lei YUbd3b0072019-08-08 13:09:50 +0800319 {
Lei YUdcaf8932019-09-09 16:09:35 +0800320 version = utils::getVersion(psuPath);
321 if (!version.empty())
Lei YUbd3b0072019-08-08 13:09:50 +0800322 {
Lei YUdcaf8932019-09-09 16:09:35 +0800323 createPsuObject(psuPath, version);
Lei YUbd3b0072019-08-08 13:09:50 +0800324 }
Lei YUbd3b0072019-08-08 13:09:50 +0800325 }
326 else
327 {
Lei YUbd3b0072019-08-08 13:09:50 +0800328 // Remove object or association
329 removePsuObject(psuPath);
330 }
Lei YUad90ad52019-08-06 11:19:28 +0800331}
332
333void ItemUpdater::processPSUImage()
334{
335 auto paths = utils::getPSUInventoryPath(bus);
336 for (const auto& p : paths)
337 {
Lei YU5f3584d2019-08-27 16:28:53 +0800338 auto service = utils::getService(bus, p.c_str(), ITEM_IFACE);
Lei YUad90ad52019-08-06 11:19:28 +0800339 auto present = utils::getProperty<bool>(bus, service.c_str(), p.c_str(),
Lei YUf77189f2019-08-07 14:26:30 +0800340 ITEM_IFACE, PRESENT);
Lei YU5f3584d2019-08-27 16:28:53 +0800341 auto version = utils::getVersion(p);
Lei YUad90ad52019-08-06 11:19:28 +0800342 if (present && !version.empty())
343 {
344 createPsuObject(p, version);
345 }
Lei YUbd3b0072019-08-08 13:09:50 +0800346 // Add matches for PSU Inventory's property changes
347 psuMatches.emplace_back(
Lei YUdcaf8932019-09-09 16:09:35 +0800348 bus, MatchRules::propertiesChanged(p, ITEM_IFACE),
Lei YUa2c2cd72019-08-09 15:54:10 +0800349 std::bind(&ItemUpdater::onPsuInventoryChangedMsg, this,
Lei YUbd3b0072019-08-08 13:09:50 +0800350 std::placeholders::_1));
Lei YUad90ad52019-08-06 11:19:28 +0800351 }
352}
353
Lei YU01539e72019-07-31 10:57:38 +0800354} // namespace updater
355} // namespace software
356} // namespace phosphor