blob: 49b95dfec45139ad38e65830a80201646c0838ce [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
Lei YUa5c47bb2019-09-29 11:28:53 +0800126void ItemUpdater::erase(const std::string& versionId)
Lei YU01539e72019-07-31 10:57:38 +0800127{
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
Lei YU91029442019-08-01 15:57:31 +0800156void ItemUpdater::createActiveAssociation(const std::string& path)
157{
158 assocs.emplace_back(
159 std::make_tuple(ACTIVE_FWD_ASSOCIATION, ACTIVE_REV_ASSOCIATION, path));
160 associations(assocs);
161}
162
Lei YUad90ad52019-08-06 11:19:28 +0800163void ItemUpdater::addFunctionalAssociation(const std::string& path)
Lei YU91029442019-08-01 15:57:31 +0800164{
Lei YU91029442019-08-01 15:57:31 +0800165 assocs.emplace_back(std::make_tuple(FUNCTIONAL_FWD_ASSOCIATION,
166 FUNCTIONAL_REV_ASSOCIATION, path));
167 associations(assocs);
168}
169
170void ItemUpdater::removeAssociation(const std::string& path)
171{
172 for (auto iter = assocs.begin(); iter != assocs.end();)
173 {
174 if ((std::get<2>(*iter)).compare(path) == 0)
175 {
176 iter = assocs.erase(iter);
177 associations(assocs);
178 }
179 else
180 {
181 ++iter;
182 }
183 }
184}
185
Lei YU01539e72019-07-31 10:57:38 +0800186std::unique_ptr<Activation> ItemUpdater::createActivationObject(
187 const std::string& path, const std::string& versionId,
188 const std::string& extVersion,
189 sdbusplus::xyz::openbmc_project::Software::server::Activation::Activations
Lei YU91029442019-08-01 15:57:31 +0800190 activationStatus,
191 const AssociationList& assocs)
Lei YU01539e72019-07-31 10:57:38 +0800192{
193 return std::make_unique<Activation>(bus, path, versionId, extVersion,
Lei YU7f2a2152019-09-16 16:50:18 +0800194 activationStatus, assocs, this);
Lei YU01539e72019-07-31 10:57:38 +0800195}
196
Lei YUad90ad52019-08-06 11:19:28 +0800197void ItemUpdater::createPsuObject(const std::string& psuInventoryPath,
198 const std::string& psuVersion)
199{
200 auto versionId = utils::getVersionId(psuVersion);
201 auto path = std::string(SOFTWARE_OBJPATH) + "/" + versionId;
202
203 auto it = activations.find(versionId);
204 if (it != activations.end())
205 {
206 // The versionId is already created, associate the path
207 auto associations = it->second->associations();
208 associations.emplace_back(std::make_tuple(ACTIVATION_FWD_ASSOCIATION,
209 ACTIVATION_REV_ASSOCIATION,
210 psuInventoryPath));
211 it->second->associations(associations);
Lei YUbd3b0072019-08-08 13:09:50 +0800212 psuPathActivationMap.emplace(psuInventoryPath, it->second);
Lei YUad90ad52019-08-06 11:19:28 +0800213 }
214 else
215 {
216 // Create a new object for running PSU inventory
217 AssociationList associations;
218 auto activationState = server::Activation::Activations::Active;
219
220 associations.emplace_back(std::make_tuple(ACTIVATION_FWD_ASSOCIATION,
221 ACTIVATION_REV_ASSOCIATION,
222 psuInventoryPath));
223
224 auto activation = createActivationObject(path, versionId, "",
225 activationState, associations);
226 activations.emplace(versionId, std::move(activation));
Lei YUbd3b0072019-08-08 13:09:50 +0800227 psuPathActivationMap.emplace(psuInventoryPath, activations[versionId]);
Lei YUad90ad52019-08-06 11:19:28 +0800228
229 auto versionPtr = createVersionObject(path, versionId, psuVersion,
230 VersionPurpose::PSU, "");
231 versions.emplace(versionId, std::move(versionPtr));
232
233 createActiveAssociation(path);
234 addFunctionalAssociation(path);
235 }
236}
237
Lei YUbd3b0072019-08-08 13:09:50 +0800238void ItemUpdater::removePsuObject(const std::string& psuInventoryPath)
239{
Lei YUbd3b0072019-08-08 13:09:50 +0800240 auto it = psuPathActivationMap.find(psuInventoryPath);
241 if (it == psuPathActivationMap.end())
242 {
243 log<level::ERR>("No Activation found for PSU",
244 entry("PSUPATH=%s", psuInventoryPath.c_str()));
245 return;
246 }
247 const auto& activationPtr = it->second;
248 psuPathActivationMap.erase(psuInventoryPath);
249
250 auto associations = activationPtr->associations();
251 for (auto iter = associations.begin(); iter != associations.end();)
252 {
253 if ((std::get<2>(*iter)).compare(psuInventoryPath) == 0)
254 {
255 iter = associations.erase(iter);
256 }
257 else
258 {
259 ++iter;
260 }
261 }
262 if (associations.empty())
263 {
264 // Remove the activation
Lei YUa5c47bb2019-09-29 11:28:53 +0800265 erase(activationPtr->getVersionId());
Lei YUbd3b0072019-08-08 13:09:50 +0800266 }
267 else
268 {
269 // Update association
270 activationPtr->associations(associations);
271 }
272}
273
Lei YU01539e72019-07-31 10:57:38 +0800274std::unique_ptr<Version> ItemUpdater::createVersionObject(
275 const std::string& objPath, const std::string& versionId,
276 const std::string& versionString,
277 sdbusplus::xyz::openbmc_project::Software::server::Version::VersionPurpose
278 versionPurpose,
279 const std::string& filePath)
280{
281 auto version = std::make_unique<Version>(
282 bus, objPath, versionId, versionString, versionPurpose, filePath,
283 std::bind(&ItemUpdater::erase, this, std::placeholders::_1));
284 return version;
285}
286
Lei YUa2c2cd72019-08-09 15:54:10 +0800287void ItemUpdater::onPsuInventoryChangedMsg(sdbusplus::message::message& msg)
Lei YUad90ad52019-08-06 11:19:28 +0800288{
Lei YUbd3b0072019-08-08 13:09:50 +0800289 using Interface = std::string;
Lei YUbd3b0072019-08-08 13:09:50 +0800290 Interface interface;
291 Properties properties;
Lei YUbd3b0072019-08-08 13:09:50 +0800292 std::string psuPath = msg.get_path();
293
294 msg.read(interface, properties);
Lei YUa2c2cd72019-08-09 15:54:10 +0800295 onPsuInventoryChanged(psuPath, properties);
296}
297
298void ItemUpdater::onPsuInventoryChanged(const std::string& psuPath,
299 const Properties& properties)
300{
Lei YUdcaf8932019-09-09 16:09:35 +0800301 bool present;
302 std::string version;
Lei YUbd3b0072019-08-08 13:09:50 +0800303
Lei YUdcaf8932019-09-09 16:09:35 +0800304 // Only present property is interested
Lei YUf77189f2019-08-07 14:26:30 +0800305 auto p = properties.find(PRESENT);
Lei YUdcaf8932019-09-09 16:09:35 +0800306 if (p == properties.end())
Lei YUbd3b0072019-08-08 13:09:50 +0800307 {
308 return;
309 }
Lei YUdcaf8932019-09-09 16:09:35 +0800310 present = sdbusplus::message::variant_ns::get<bool>(p->second);
Lei YUbd3b0072019-08-08 13:09:50 +0800311
Lei YUdcaf8932019-09-09 16:09:35 +0800312 if (present)
Lei YUbd3b0072019-08-08 13:09:50 +0800313 {
Lei YUdcaf8932019-09-09 16:09:35 +0800314 version = utils::getVersion(psuPath);
315 if (!version.empty())
Lei YUbd3b0072019-08-08 13:09:50 +0800316 {
Lei YUdcaf8932019-09-09 16:09:35 +0800317 createPsuObject(psuPath, version);
Lei YUbd3b0072019-08-08 13:09:50 +0800318 }
Lei YUbd3b0072019-08-08 13:09:50 +0800319 }
320 else
321 {
Lei YUbd3b0072019-08-08 13:09:50 +0800322 // Remove object or association
323 removePsuObject(psuPath);
324 }
Lei YUad90ad52019-08-06 11:19:28 +0800325}
326
327void ItemUpdater::processPSUImage()
328{
329 auto paths = utils::getPSUInventoryPath(bus);
330 for (const auto& p : paths)
331 {
Lei YU5f3584d2019-08-27 16:28:53 +0800332 auto service = utils::getService(bus, p.c_str(), ITEM_IFACE);
Lei YUad90ad52019-08-06 11:19:28 +0800333 auto present = utils::getProperty<bool>(bus, service.c_str(), p.c_str(),
Lei YUf77189f2019-08-07 14:26:30 +0800334 ITEM_IFACE, PRESENT);
Lei YU5f3584d2019-08-27 16:28:53 +0800335 auto version = utils::getVersion(p);
Lei YUad90ad52019-08-06 11:19:28 +0800336 if (present && !version.empty())
337 {
338 createPsuObject(p, version);
339 }
Lei YUbd3b0072019-08-08 13:09:50 +0800340 // Add matches for PSU Inventory's property changes
341 psuMatches.emplace_back(
Lei YUdcaf8932019-09-09 16:09:35 +0800342 bus, MatchRules::propertiesChanged(p, ITEM_IFACE),
Lei YUa2c2cd72019-08-09 15:54:10 +0800343 std::bind(&ItemUpdater::onPsuInventoryChangedMsg, this,
Lei YUbd3b0072019-08-08 13:09:50 +0800344 std::placeholders::_1));
Lei YUad90ad52019-08-06 11:19:28 +0800345 }
346}
347
Lei YU01539e72019-07-31 10:57:38 +0800348} // namespace updater
349} // namespace software
350} // namespace phosphor