12d8fa225SAdriana Kobylak #include "config.h"
2f6ed5897SGunnar Mills
32d8fa225SAdriana Kobylak #include "item_updater.hpp"
4f6ed5897SGunnar Mills
5f6ed5897SGunnar Mills #include "xyz/openbmc_project/Common/error.hpp"
6f6ed5897SGunnar Mills
7f6ed5897SGunnar Mills #include <phosphor-logging/elog-errors.hpp>
8f6ed5897SGunnar Mills #include <phosphor-logging/log.hpp>
92d8fa225SAdriana Kobylak
108facccfaSBrad Bishop #include <filesystem>
118facccfaSBrad Bishop
122d8fa225SAdriana Kobylak namespace openpower
132d8fa225SAdriana Kobylak {
142d8fa225SAdriana Kobylak namespace software
152d8fa225SAdriana Kobylak {
16befe5ce4SAdriana Kobylak namespace updater
172d8fa225SAdriana Kobylak {
18a9ac9279SLei YU namespace server = sdbusplus::xyz::openbmc_project::Software::server;
19a9ac9279SLei YU namespace fs = std::filesystem;
20a9ac9279SLei YU
2113fc66adSEddie James using namespace sdbusplus::xyz::openbmc_project::Common::Error;
22b66ac3aeSAdriana Kobylak using namespace phosphor::logging;
23b66ac3aeSAdriana Kobylak
createActivation(sdbusplus::message_t & m)240dea1992SPatrick Williams void ItemUpdater::createActivation(sdbusplus::message_t& m)
25a9ac9279SLei YU {
26a9ac9279SLei YU using SVersion = server::Version;
27a9ac9279SLei YU using VersionPurpose = SVersion::VersionPurpose;
28a9ac9279SLei YU
29a9ac9279SLei YU sdbusplus::message::object_path objPath;
30573552aeSPatrick Williams std::map<std::string, std::map<std::string, std::variant<std::string>>>
31a9ac9279SLei YU interfaces;
32a9ac9279SLei YU m.read(objPath, interfaces);
33a9ac9279SLei YU
34a9ac9279SLei YU std::string path(std::move(objPath));
35a9ac9279SLei YU std::string filePath;
36a9ac9279SLei YU auto purpose = VersionPurpose::Unknown;
37a9ac9279SLei YU std::string version;
38a9ac9279SLei YU
39a9ac9279SLei YU for (const auto& intf : interfaces)
40a9ac9279SLei YU {
41a9ac9279SLei YU if (intf.first == VERSION_IFACE)
42a9ac9279SLei YU {
43a9ac9279SLei YU for (const auto& property : intf.second)
44a9ac9279SLei YU {
45a9ac9279SLei YU if (property.first == "Purpose")
46a9ac9279SLei YU {
47a9ac9279SLei YU // Only process the Host and System images
48a9ac9279SLei YU auto value = SVersion::convertVersionPurposeFromString(
49550f31b3SPatrick Williams std::get<std::string>(property.second));
50a9ac9279SLei YU
51a9ac9279SLei YU if (value == VersionPurpose::Host ||
52a9ac9279SLei YU value == VersionPurpose::System)
53a9ac9279SLei YU {
54a9ac9279SLei YU purpose = value;
55a9ac9279SLei YU }
56a9ac9279SLei YU }
57a9ac9279SLei YU else if (property.first == "Version")
58a9ac9279SLei YU {
59550f31b3SPatrick Williams version = std::get<std::string>(property.second);
60a9ac9279SLei YU }
61a9ac9279SLei YU }
62a9ac9279SLei YU }
63a9ac9279SLei YU else if (intf.first == FILEPATH_IFACE)
64a9ac9279SLei YU {
65a9ac9279SLei YU for (const auto& property : intf.second)
66a9ac9279SLei YU {
67a9ac9279SLei YU if (property.first == "Path")
68a9ac9279SLei YU {
69550f31b3SPatrick Williams filePath = std::get<std::string>(property.second);
70a9ac9279SLei YU }
71a9ac9279SLei YU }
72a9ac9279SLei YU }
73a9ac9279SLei YU }
74a9ac9279SLei YU if ((filePath.empty()) || (purpose == VersionPurpose::Unknown))
75a9ac9279SLei YU {
76a9ac9279SLei YU return;
77a9ac9279SLei YU }
78a9ac9279SLei YU
79a9ac9279SLei YU // Version id is the last item in the path
80a9ac9279SLei YU auto pos = path.rfind("/");
81a9ac9279SLei YU if (pos == std::string::npos)
82a9ac9279SLei YU {
83a9ac9279SLei YU log<level::ERR>("No version id found in object path",
84a9ac9279SLei YU entry("OBJPATH=%s", path.c_str()));
85a9ac9279SLei YU return;
86a9ac9279SLei YU }
87a9ac9279SLei YU
88a9ac9279SLei YU auto versionId = path.substr(pos + 1);
89a9ac9279SLei YU
90a9ac9279SLei YU if (activations.find(versionId) == activations.end())
91a9ac9279SLei YU {
92a9ac9279SLei YU // Determine the Activation state by processing the given image dir.
93a9ac9279SLei YU auto activationState = server::Activation::Activations::Invalid;
94a9ac9279SLei YU AssociationList associations = {};
95a9ac9279SLei YU if (validateImage(filePath))
96a9ac9279SLei YU {
97a9ac9279SLei YU activationState = server::Activation::Activations::Ready;
98a9ac9279SLei YU // Create an association to the host inventory item
99a9ac9279SLei YU associations.emplace_back(std::make_tuple(
100a9ac9279SLei YU ACTIVATION_FWD_ASSOCIATION, ACTIVATION_REV_ASSOCIATION,
101a9ac9279SLei YU HOST_INVENTORY_PATH));
102a9ac9279SLei YU }
103a9ac9279SLei YU
104a9ac9279SLei YU fs::path manifestPath(filePath);
105a9ac9279SLei YU manifestPath /= MANIFEST_FILE;
106a9ac9279SLei YU std::string extendedVersion =
107a9ac9279SLei YU (Version::getValue(
108a9ac9279SLei YU manifestPath.string(),
109a9ac9279SLei YU std::map<std::string, std::string>{{"extended_version", ""}}))
110a9ac9279SLei YU .begin()
111a9ac9279SLei YU ->second;
112a9ac9279SLei YU
113a9ac9279SLei YU auto activation = createActivationObject(
114a9ac9279SLei YU path, versionId, extendedVersion, activationState, associations);
115a9ac9279SLei YU activations.emplace(versionId, std::move(activation));
116a9ac9279SLei YU
117*7fb6c346SPatrick Williams auto versionPtr = createVersionObject(path, versionId, version, purpose,
118*7fb6c346SPatrick Williams filePath);
119a9ac9279SLei YU versions.emplace(versionId, std::move(versionPtr));
120a9ac9279SLei YU }
121a9ac9279SLei YU return;
122a9ac9279SLei YU }
123a9ac9279SLei YU
createActiveAssociation(const std::string & path)124f3ce4337SLei YU void ItemUpdater::createActiveAssociation(const std::string& path)
1252d8fa225SAdriana Kobylak {
126f3ce4337SLei YU assocs.emplace_back(
127f3ce4337SLei YU std::make_tuple(ACTIVE_FWD_ASSOCIATION, ACTIVE_REV_ASSOCIATION, path));
128f3ce4337SLei YU associations(assocs);
129b66ac3aeSAdriana Kobylak }
130b66ac3aeSAdriana Kobylak
createUpdateableAssociation(const std::string & path)1313c81037eSAdriana Kobylak void ItemUpdater::createUpdateableAssociation(const std::string& path)
1323c81037eSAdriana Kobylak {
1333c81037eSAdriana Kobylak assocs.emplace_back(std::make_tuple(UPDATEABLE_FWD_ASSOCIATION,
1343c81037eSAdriana Kobylak UPDATEABLE_REV_ASSOCIATION, path));
1353c81037eSAdriana Kobylak associations(assocs);
1363c81037eSAdriana Kobylak }
1373c81037eSAdriana Kobylak
updateFunctionalAssociation(const std::string & versionId)138f3ce4337SLei YU void ItemUpdater::updateFunctionalAssociation(const std::string& versionId)
139b66ac3aeSAdriana Kobylak {
140f3ce4337SLei YU std::string path = std::string{SOFTWARE_OBJPATH} + '/' + versionId;
141f3ce4337SLei YU // remove all functional associations
142f3ce4337SLei YU for (auto iter = assocs.begin(); iter != assocs.end();)
1432fdb9310SAdriana Kobylak {
144f3ce4337SLei YU if ((std::get<0>(*iter)).compare(FUNCTIONAL_FWD_ASSOCIATION) == 0)
145a8ade7e4SSaqib Khan {
146f3ce4337SLei YU iter = assocs.erase(iter);
147a8ade7e4SSaqib Khan }
148a8ade7e4SSaqib Khan else
149a8ade7e4SSaqib Khan {
150f3ce4337SLei YU ++iter;
151a8ade7e4SSaqib Khan }
152a8ade7e4SSaqib Khan }
153f3ce4337SLei YU assocs.emplace_back(std::make_tuple(FUNCTIONAL_FWD_ASSOCIATION,
154f3ce4337SLei YU FUNCTIONAL_REV_ASSOCIATION, path));
155f3ce4337SLei YU associations(assocs);
1569c8adfa3SLeonel Gonzalez }
1579c8adfa3SLeonel Gonzalez
removeAssociation(const std::string & path)158f3ce4337SLei YU void ItemUpdater::removeAssociation(const std::string& path)
159dd961b6cSMichael Tritz {
160f3ce4337SLei YU for (auto iter = assocs.begin(); iter != assocs.end();)
161f3ce4337SLei YU {
162f3ce4337SLei YU if ((std::get<2>(*iter)).compare(path) == 0)
163f3ce4337SLei YU {
164f3ce4337SLei YU iter = assocs.erase(iter);
165f3ce4337SLei YU associations(assocs);
166dd961b6cSMichael Tritz }
167f3ce4337SLei YU else
1689c8adfa3SLeonel Gonzalez {
169f3ce4337SLei YU ++iter;
170dd961b6cSMichael Tritz }
1719c8adfa3SLeonel Gonzalez }
172ca9ba069SAdriana Kobylak }
173ca9ba069SAdriana Kobylak
erase(std::string entryId)174f3ce4337SLei YU bool ItemUpdater::erase(std::string entryId)
175fa7aa12cSMichael Tritz {
176f3ce4337SLei YU if (isVersionFunctional(entryId) && isChassisOn())
177ca9ba069SAdriana Kobylak {
178f3ce4337SLei YU log<level::ERR>(("Error: Version " + entryId +
179f3ce4337SLei YU " is currently active and running on the host."
180f3ce4337SLei YU " Unable to remove.")
181f3ce4337SLei YU .c_str());
18213fc66adSEddie James return false;
18313fc66adSEddie James }
18413fc66adSEddie James
185f3ce4337SLei YU // Removing entry in versions map
186f3ce4337SLei YU auto it = versions.find(entryId);
187f3ce4337SLei YU if (it == versions.end())
18813fc66adSEddie James {
189f3ce4337SLei YU log<level::ERR>(("Error: Failed to find version " + entryId +
190f3ce4337SLei YU " in item updater versions map."
191f3ce4337SLei YU " Unable to remove.")
192f3ce4337SLei YU .c_str());
193f3ce4337SLei YU }
194f3ce4337SLei YU else
195f3ce4337SLei YU {
196f3ce4337SLei YU versions.erase(entryId);
19713fc66adSEddie James }
19813fc66adSEddie James
199f3ce4337SLei YU // Removing entry in activations map
200f3ce4337SLei YU auto ita = activations.find(entryId);
201f3ce4337SLei YU if (ita == activations.end())
20213fc66adSEddie James {
203f3ce4337SLei YU log<level::ERR>(("Error: Failed to find version " + entryId +
204f3ce4337SLei YU " in item updater activations map."
205f3ce4337SLei YU " Unable to remove.")
206f3ce4337SLei YU .c_str());
20713fc66adSEddie James }
208f3ce4337SLei YU else
209f3ce4337SLei YU {
210f3ce4337SLei YU removeAssociation(ita->second->path);
211f3ce4337SLei YU activations.erase(entryId);
212f3ce4337SLei YU }
21313fc66adSEddie James return true;
21413fc66adSEddie James }
21513fc66adSEddie James
isChassisOn()21613fc66adSEddie James bool ItemUpdater::isChassisOn()
21713fc66adSEddie James {
21870dcb63aSAdriana Kobylak auto mapperCall = bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH,
21970dcb63aSAdriana Kobylak MAPPER_INTERFACE, "GetObject");
22013fc66adSEddie James
22113fc66adSEddie James mapperCall.append(CHASSIS_STATE_PATH,
22213fc66adSEddie James std::vector<std::string>({CHASSIS_STATE_OBJ}));
223b8cb0cc9SAdriana Kobylak
224b8cb0cc9SAdriana Kobylak std::map<std::string, std::vector<std::string>> mapperResponse;
225b8cb0cc9SAdriana Kobylak
226b8cb0cc9SAdriana Kobylak try
22713fc66adSEddie James {
228b8cb0cc9SAdriana Kobylak auto mapperResponseMsg = bus.call(mapperCall);
22913fc66adSEddie James mapperResponseMsg.read(mapperResponse);
23013fc66adSEddie James if (mapperResponse.empty())
23113fc66adSEddie James {
23213fc66adSEddie James log<level::ERR>("Invalid Response from mapper");
23313fc66adSEddie James elog<InternalFailure>();
23413fc66adSEddie James }
235b8cb0cc9SAdriana Kobylak }
2360dea1992SPatrick Williams catch (const sdbusplus::exception_t& e)
237b8cb0cc9SAdriana Kobylak {
238b8cb0cc9SAdriana Kobylak log<level::ERR>("Error in Mapper call");
239b8cb0cc9SAdriana Kobylak elog<InternalFailure>();
240b8cb0cc9SAdriana Kobylak }
24113fc66adSEddie James
24213fc66adSEddie James auto method = bus.new_method_call((mapperResponse.begin()->first).c_str(),
24313fc66adSEddie James CHASSIS_STATE_PATH,
24470dcb63aSAdriana Kobylak SYSTEMD_PROPERTY_INTERFACE, "Get");
24513fc66adSEddie James method.append(CHASSIS_STATE_OBJ, "CurrentPowerState");
246b8cb0cc9SAdriana Kobylak
247212102e6SPatrick Williams std::variant<std::string> currentChassisState;
248b8cb0cc9SAdriana Kobylak
249b8cb0cc9SAdriana Kobylak try
250b8cb0cc9SAdriana Kobylak {
25113fc66adSEddie James auto response = bus.call(method);
252b8cb0cc9SAdriana Kobylak response.read(currentChassisState);
253550f31b3SPatrick Williams auto strParam = std::get<std::string>(currentChassisState);
254b8cb0cc9SAdriana Kobylak return (strParam != CHASSIS_STATE_OFF);
255b8cb0cc9SAdriana Kobylak }
2560dea1992SPatrick Williams catch (const sdbusplus::exception_t& e)
25713fc66adSEddie James {
25813fc66adSEddie James log<level::ERR>("Error in fetching current Chassis State",
259850d5f6bSGunnar Mills entry("MAPPERRESPONSE=%s",
26013fc66adSEddie James (mapperResponse.begin()->first).c_str()));
26113fc66adSEddie James elog<InternalFailure>();
26213fc66adSEddie James }
26313fc66adSEddie James }
26413fc66adSEddie James
265befe5ce4SAdriana Kobylak } // namespace updater
2662d8fa225SAdriana Kobylak } // namespace software
2672d8fa225SAdriana Kobylak } // namespace openpower
268