blob: 32e046c7ac0c6664f6df0377434cfba552643045 [file] [log] [blame]
Adriana Kobylak2d8fa222017-03-15 12:34:32 -05001#include "config.h"
Gunnar Millsf6ed5892018-09-07 17:08:02 -05002
Adriana Kobylak2d8fa222017-03-15 12:34:32 -05003#include "item_updater.hpp"
Gunnar Millsf6ed5892018-09-07 17:08:02 -05004
Gunnar Millsf6ed5892018-09-07 17:08:02 -05005#include "xyz/openbmc_project/Common/error.hpp"
6
Lei YUa9ac9272019-02-22 16:38:35 +08007#include <filesystem>
Gunnar Millsf6ed5892018-09-07 17:08:02 -05008#include <phosphor-logging/elog-errors.hpp>
9#include <phosphor-logging/log.hpp>
Adriana Kobylak2d8fa222017-03-15 12:34:32 -050010
11namespace openpower
12{
13namespace software
14{
Adriana Kobylakbefe5ce2017-04-05 15:57:44 -050015namespace updater
Adriana Kobylak2d8fa222017-03-15 12:34:32 -050016{
Lei YUa9ac9272019-02-22 16:38:35 +080017namespace server = sdbusplus::xyz::openbmc_project::Software::server;
18namespace fs = std::filesystem;
19
Eddie James13fc66a2017-08-31 15:36:44 -050020using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Adriana Kobylakb66ac3a2017-03-28 13:33:20 -050021using namespace phosphor::logging;
22
Lei YUa9ac9272019-02-22 16:38:35 +080023void ItemUpdater::createActivation(sdbusplus::message::message& m)
24{
25 using SVersion = server::Version;
26 using VersionPurpose = SVersion::VersionPurpose;
27 namespace msg = sdbusplus::message;
Lei YUa9ac9272019-02-22 16:38:35 +080028
29 sdbusplus::message::object_path objPath;
30 std::map<std::string, std::map<std::string, msg::variant<std::string>>>
31 interfaces;
32 m.read(objPath, interfaces);
33
34 std::string path(std::move(objPath));
35 std::string filePath;
36 auto purpose = VersionPurpose::Unknown;
37 std::string version;
38
39 for (const auto& intf : interfaces)
40 {
41 if (intf.first == VERSION_IFACE)
42 {
43 for (const auto& property : intf.second)
44 {
45 if (property.first == "Purpose")
46 {
47 // Only process the Host and System images
48 auto value = SVersion::convertVersionPurposeFromString(
Patrick Williams550f31b2020-05-13 11:15:24 -050049 std::get<std::string>(property.second));
Lei YUa9ac9272019-02-22 16:38:35 +080050
51 if (value == VersionPurpose::Host ||
52 value == VersionPurpose::System)
53 {
54 purpose = value;
55 }
56 }
57 else if (property.first == "Version")
58 {
Patrick Williams550f31b2020-05-13 11:15:24 -050059 version = std::get<std::string>(property.second);
Lei YUa9ac9272019-02-22 16:38:35 +080060 }
61 }
62 }
63 else if (intf.first == FILEPATH_IFACE)
64 {
65 for (const auto& property : intf.second)
66 {
67 if (property.first == "Path")
68 {
Patrick Williams550f31b2020-05-13 11:15:24 -050069 filePath = std::get<std::string>(property.second);
Lei YUa9ac9272019-02-22 16:38:35 +080070 }
71 }
72 }
73 }
74 if ((filePath.empty()) || (purpose == VersionPurpose::Unknown))
75 {
76 return;
77 }
78
79 // Version id is the last item in the path
80 auto pos = path.rfind("/");
81 if (pos == std::string::npos)
82 {
83 log<level::ERR>("No version id found in object path",
84 entry("OBJPATH=%s", path.c_str()));
85 return;
86 }
87
88 auto versionId = path.substr(pos + 1);
89
90 if (activations.find(versionId) == activations.end())
91 {
92 // Determine the Activation state by processing the given image dir.
93 auto activationState = server::Activation::Activations::Invalid;
94 AssociationList associations = {};
95 if (validateImage(filePath))
96 {
97 activationState = server::Activation::Activations::Ready;
98 // Create an association to the host inventory item
99 associations.emplace_back(std::make_tuple(
100 ACTIVATION_FWD_ASSOCIATION, ACTIVATION_REV_ASSOCIATION,
101 HOST_INVENTORY_PATH));
102 }
103
104 fs::path manifestPath(filePath);
105 manifestPath /= MANIFEST_FILE;
106 std::string extendedVersion =
107 (Version::getValue(
108 manifestPath.string(),
109 std::map<std::string, std::string>{{"extended_version", ""}}))
110 .begin()
111 ->second;
112
113 auto activation = createActivationObject(
114 path, versionId, extendedVersion, activationState, associations);
115 activations.emplace(versionId, std::move(activation));
116
117 auto versionPtr =
118 createVersionObject(path, versionId, version, purpose, filePath);
119 versions.emplace(versionId, std::move(versionPtr));
120 }
121 return;
122}
123
Lei YUf3ce4332019-02-21 14:09:49 +0800124void ItemUpdater::createActiveAssociation(const std::string& path)
Adriana Kobylak2d8fa222017-03-15 12:34:32 -0500125{
Lei YUf3ce4332019-02-21 14:09:49 +0800126 assocs.emplace_back(
127 std::make_tuple(ACTIVE_FWD_ASSOCIATION, ACTIVE_REV_ASSOCIATION, path));
128 associations(assocs);
Adriana Kobylak2d8fa222017-03-15 12:34:32 -0500129}
130
Lei YUf3ce4332019-02-21 14:09:49 +0800131void ItemUpdater::updateFunctionalAssociation(const std::string& versionId)
Saqib Khan7254f0e2017-04-10 21:45:37 -0500132{
Lei YUf3ce4332019-02-21 14:09:49 +0800133 std::string path = std::string{SOFTWARE_OBJPATH} + '/' + versionId;
134 // remove all functional associations
135 for (auto iter = assocs.begin(); iter != assocs.end();)
Saqib Khan4c5d7442017-07-18 00:43:52 -0500136 {
Lei YUf3ce4332019-02-21 14:09:49 +0800137 if ((std::get<0>(*iter)).compare(FUNCTIONAL_FWD_ASSOCIATION) == 0)
Saqib Khan4c5d7442017-07-18 00:43:52 -0500138 {
Lei YUf3ce4332019-02-21 14:09:49 +0800139 iter = assocs.erase(iter);
Saqib Khan4c5d7442017-07-18 00:43:52 -0500140 }
Lei YUf3ce4332019-02-21 14:09:49 +0800141 else
Saqib Khan2be9ba92017-09-26 22:44:10 -0500142 {
Lei YUf3ce4332019-02-21 14:09:49 +0800143 ++iter;
Saqib Khan2be9ba92017-09-26 22:44:10 -0500144 }
Saqib Khan4c5d7442017-07-18 00:43:52 -0500145 }
Lei YUf3ce4332019-02-21 14:09:49 +0800146 assocs.emplace_back(std::make_tuple(FUNCTIONAL_FWD_ASSOCIATION,
147 FUNCTIONAL_REV_ASSOCIATION, path));
148 associations(assocs);
Saqib Khan7254f0e2017-04-10 21:45:37 -0500149}
150
Lei YUf3ce4332019-02-21 14:09:49 +0800151void ItemUpdater::removeAssociation(const std::string& path)
Saqib Khana8ade7e2017-04-12 10:27:56 -0500152{
Lei YUf3ce4332019-02-21 14:09:49 +0800153 for (auto iter = assocs.begin(); iter != assocs.end();)
Saqib Khana8ade7e2017-04-12 10:27:56 -0500154 {
Lei YUf3ce4332019-02-21 14:09:49 +0800155 if ((std::get<2>(*iter)).compare(path) == 0)
156 {
157 iter = assocs.erase(iter);
158 associations(assocs);
159 }
160 else
161 {
162 ++iter;
163 }
164 }
165}
166
167bool ItemUpdater::erase(std::string entryId)
168{
169 if (isVersionFunctional(entryId) && isChassisOn())
170 {
171 log<level::ERR>(("Error: Version " + entryId +
172 " is currently active and running on the host."
173 " Unable to remove.")
174 .c_str());
175 return false;
176 }
177
178 // Removing entry in versions map
179 auto it = versions.find(entryId);
180 if (it == versions.end())
181 {
182 log<level::ERR>(("Error: Failed to find version " + entryId +
183 " in item updater versions map."
184 " Unable to remove.")
185 .c_str());
Saqib Khana8ade7e2017-04-12 10:27:56 -0500186 }
187 else
188 {
Lei YUf3ce4332019-02-21 14:09:49 +0800189 versions.erase(entryId);
Saqib Khana8ade7e2017-04-12 10:27:56 -0500190 }
Saqib Khana8ade7e2017-04-12 10:27:56 -0500191
Lei YUf3ce4332019-02-21 14:09:49 +0800192 // Removing entry in activations map
193 auto ita = activations.find(entryId);
194 if (ita == activations.end())
Adriana Kobylak0bd65052018-07-09 10:55:56 -0500195 {
Lei YUf3ce4332019-02-21 14:09:49 +0800196 log<level::ERR>(("Error: Failed to find version " + entryId +
197 " in item updater activations map."
198 " Unable to remove.")
199 .c_str());
Adriana Kobylak0bd65052018-07-09 10:55:56 -0500200 }
Lei YUf3ce4332019-02-21 14:09:49 +0800201 else
Michael Tritzbb31f022017-11-22 11:51:29 -0600202 {
Lei YUf3ce4332019-02-21 14:09:49 +0800203 removeAssociation(ita->second->path);
204 activations.erase(entryId);
Michael Tritzbb31f022017-11-22 11:51:29 -0600205 }
Eddie James13fc66a2017-08-31 15:36:44 -0500206 return true;
207}
208
209bool ItemUpdater::isChassisOn()
210{
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600211 auto mapperCall = bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH,
212 MAPPER_INTERFACE, "GetObject");
Eddie James13fc66a2017-08-31 15:36:44 -0500213
214 mapperCall.append(CHASSIS_STATE_PATH,
215 std::vector<std::string>({CHASSIS_STATE_OBJ}));
Adriana Kobylakb8cb0cc2019-05-31 09:58:04 -0500216
217 std::map<std::string, std::vector<std::string>> mapperResponse;
218
219 try
220 {
221 auto mapperResponseMsg = bus.call(mapperCall);
222 mapperResponseMsg.read(mapperResponse);
223 if (mapperResponse.empty())
224 {
225 log<level::ERR>("Invalid Response from mapper");
226 elog<InternalFailure>();
227 }
228 }
229 catch (const sdbusplus::exception::SdBusError& e)
Eddie James13fc66a2017-08-31 15:36:44 -0500230 {
231 log<level::ERR>("Error in Mapper call");
232 elog<InternalFailure>();
233 }
Eddie James13fc66a2017-08-31 15:36:44 -0500234
235 auto method = bus.new_method_call((mapperResponse.begin()->first).c_str(),
236 CHASSIS_STATE_PATH,
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600237 SYSTEMD_PROPERTY_INTERFACE, "Get");
Eddie James13fc66a2017-08-31 15:36:44 -0500238 method.append(CHASSIS_STATE_OBJ, "CurrentPowerState");
Adriana Kobylakb8cb0cc2019-05-31 09:58:04 -0500239
240 sdbusplus::message::variant<std::string> currentChassisState;
241
242 try
243 {
244 auto response = bus.call(method);
245 response.read(currentChassisState);
Patrick Williams550f31b2020-05-13 11:15:24 -0500246 auto strParam = std::get<std::string>(currentChassisState);
Adriana Kobylakb8cb0cc2019-05-31 09:58:04 -0500247 return (strParam != CHASSIS_STATE_OFF);
248 }
249 catch (const sdbusplus::exception::SdBusError& e)
Eddie James13fc66a2017-08-31 15:36:44 -0500250 {
251 log<level::ERR>("Error in fetching current Chassis State",
Gunnar Mills850d5f62017-10-19 17:04:38 -0500252 entry("MAPPERRESPONSE=%s",
Eddie James13fc66a2017-08-31 15:36:44 -0500253 (mapperResponse.begin()->first).c_str()));
254 elog<InternalFailure>();
255 }
Eddie James13fc66a2017-08-31 15:36:44 -0500256}
257
Adriana Kobylakbefe5ce2017-04-05 15:57:44 -0500258} // namespace updater
Adriana Kobylak2d8fa222017-03-15 12:34:32 -0500259} // namespace software
260} // namespace openpower