blob: 882acbbb7486f502ea242d3a076bcec0923192eb [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;
28 namespace variant_ns = msg::variant_ns;
29
30 sdbusplus::message::object_path objPath;
31 std::map<std::string, std::map<std::string, msg::variant<std::string>>>
32 interfaces;
33 m.read(objPath, interfaces);
34
35 std::string path(std::move(objPath));
36 std::string filePath;
37 auto purpose = VersionPurpose::Unknown;
38 std::string version;
39
40 for (const auto& intf : interfaces)
41 {
42 if (intf.first == VERSION_IFACE)
43 {
44 for (const auto& property : intf.second)
45 {
46 if (property.first == "Purpose")
47 {
48 // Only process the Host and System images
49 auto value = SVersion::convertVersionPurposeFromString(
50 variant_ns::get<std::string>(property.second));
51
52 if (value == VersionPurpose::Host ||
53 value == VersionPurpose::System)
54 {
55 purpose = value;
56 }
57 }
58 else if (property.first == "Version")
59 {
60 version = variant_ns::get<std::string>(property.second);
61 }
62 }
63 }
64 else if (intf.first == FILEPATH_IFACE)
65 {
66 for (const auto& property : intf.second)
67 {
68 if (property.first == "Path")
69 {
70 filePath = variant_ns::get<std::string>(property.second);
71 }
72 }
73 }
74 }
75 if ((filePath.empty()) || (purpose == VersionPurpose::Unknown))
76 {
77 return;
78 }
79
80 // Version id is the last item in the path
81 auto pos = path.rfind("/");
82 if (pos == std::string::npos)
83 {
84 log<level::ERR>("No version id found in object path",
85 entry("OBJPATH=%s", path.c_str()));
86 return;
87 }
88
89 auto versionId = path.substr(pos + 1);
90
91 if (activations.find(versionId) == activations.end())
92 {
93 // Determine the Activation state by processing the given image dir.
94 auto activationState = server::Activation::Activations::Invalid;
95 AssociationList associations = {};
96 if (validateImage(filePath))
97 {
98 activationState = server::Activation::Activations::Ready;
99 // Create an association to the host inventory item
100 associations.emplace_back(std::make_tuple(
101 ACTIVATION_FWD_ASSOCIATION, ACTIVATION_REV_ASSOCIATION,
102 HOST_INVENTORY_PATH));
103 }
104
105 fs::path manifestPath(filePath);
106 manifestPath /= MANIFEST_FILE;
107 std::string extendedVersion =
108 (Version::getValue(
109 manifestPath.string(),
110 std::map<std::string, std::string>{{"extended_version", ""}}))
111 .begin()
112 ->second;
113
114 auto activation = createActivationObject(
115 path, versionId, extendedVersion, activationState, associations);
116 activations.emplace(versionId, std::move(activation));
117
118 auto versionPtr =
119 createVersionObject(path, versionId, version, purpose, filePath);
120 versions.emplace(versionId, std::move(versionPtr));
121 }
122 return;
123}
124
Lei YUf3ce4332019-02-21 14:09:49 +0800125void ItemUpdater::createActiveAssociation(const std::string& path)
Adriana Kobylak2d8fa222017-03-15 12:34:32 -0500126{
Lei YUf3ce4332019-02-21 14:09:49 +0800127 assocs.emplace_back(
128 std::make_tuple(ACTIVE_FWD_ASSOCIATION, ACTIVE_REV_ASSOCIATION, path));
129 associations(assocs);
Adriana Kobylak2d8fa222017-03-15 12:34:32 -0500130}
131
Lei YUf3ce4332019-02-21 14:09:49 +0800132void ItemUpdater::updateFunctionalAssociation(const std::string& versionId)
Saqib Khan7254f0e2017-04-10 21:45:37 -0500133{
Lei YUf3ce4332019-02-21 14:09:49 +0800134 std::string path = std::string{SOFTWARE_OBJPATH} + '/' + versionId;
135 // remove all functional associations
136 for (auto iter = assocs.begin(); iter != assocs.end();)
Saqib Khan4c5d7442017-07-18 00:43:52 -0500137 {
Lei YUf3ce4332019-02-21 14:09:49 +0800138 if ((std::get<0>(*iter)).compare(FUNCTIONAL_FWD_ASSOCIATION) == 0)
Saqib Khan4c5d7442017-07-18 00:43:52 -0500139 {
Lei YUf3ce4332019-02-21 14:09:49 +0800140 iter = assocs.erase(iter);
Saqib Khan4c5d7442017-07-18 00:43:52 -0500141 }
Lei YUf3ce4332019-02-21 14:09:49 +0800142 else
Saqib Khan2be9ba92017-09-26 22:44:10 -0500143 {
Lei YUf3ce4332019-02-21 14:09:49 +0800144 ++iter;
Saqib Khan2be9ba92017-09-26 22:44:10 -0500145 }
Saqib Khan4c5d7442017-07-18 00:43:52 -0500146 }
Lei YUf3ce4332019-02-21 14:09:49 +0800147 assocs.emplace_back(std::make_tuple(FUNCTIONAL_FWD_ASSOCIATION,
148 FUNCTIONAL_REV_ASSOCIATION, path));
149 associations(assocs);
Saqib Khan7254f0e2017-04-10 21:45:37 -0500150}
151
Lei YUf3ce4332019-02-21 14:09:49 +0800152void ItemUpdater::removeAssociation(const std::string& path)
Saqib Khana8ade7e2017-04-12 10:27:56 -0500153{
Lei YUf3ce4332019-02-21 14:09:49 +0800154 for (auto iter = assocs.begin(); iter != assocs.end();)
Saqib Khana8ade7e2017-04-12 10:27:56 -0500155 {
Lei YUf3ce4332019-02-21 14:09:49 +0800156 if ((std::get<2>(*iter)).compare(path) == 0)
157 {
158 iter = assocs.erase(iter);
159 associations(assocs);
160 }
161 else
162 {
163 ++iter;
164 }
165 }
166}
167
168bool ItemUpdater::erase(std::string entryId)
169{
170 if (isVersionFunctional(entryId) && isChassisOn())
171 {
172 log<level::ERR>(("Error: Version " + entryId +
173 " is currently active and running on the host."
174 " Unable to remove.")
175 .c_str());
176 return false;
177 }
178
179 // Removing entry in versions map
180 auto it = versions.find(entryId);
181 if (it == versions.end())
182 {
183 log<level::ERR>(("Error: Failed to find version " + entryId +
184 " in item updater versions map."
185 " Unable to remove.")
186 .c_str());
Saqib Khana8ade7e2017-04-12 10:27:56 -0500187 }
188 else
189 {
Lei YUf3ce4332019-02-21 14:09:49 +0800190 versions.erase(entryId);
Saqib Khana8ade7e2017-04-12 10:27:56 -0500191 }
Saqib Khana8ade7e2017-04-12 10:27:56 -0500192
Lei YUf3ce4332019-02-21 14:09:49 +0800193 // Removing entry in activations map
194 auto ita = activations.find(entryId);
195 if (ita == activations.end())
Adriana Kobylak0bd65052018-07-09 10:55:56 -0500196 {
Lei YUf3ce4332019-02-21 14:09:49 +0800197 log<level::ERR>(("Error: Failed to find version " + entryId +
198 " in item updater activations map."
199 " Unable to remove.")
200 .c_str());
Adriana Kobylak0bd65052018-07-09 10:55:56 -0500201 }
Lei YUf3ce4332019-02-21 14:09:49 +0800202 else
Michael Tritzbb31f022017-11-22 11:51:29 -0600203 {
Lei YUf3ce4332019-02-21 14:09:49 +0800204 removeAssociation(ita->second->path);
205 activations.erase(entryId);
Michael Tritzbb31f022017-11-22 11:51:29 -0600206 }
Eddie James13fc66a2017-08-31 15:36:44 -0500207 return true;
208}
209
210bool ItemUpdater::isChassisOn()
211{
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600212 auto mapperCall = bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH,
213 MAPPER_INTERFACE, "GetObject");
Eddie James13fc66a2017-08-31 15:36:44 -0500214
215 mapperCall.append(CHASSIS_STATE_PATH,
216 std::vector<std::string>({CHASSIS_STATE_OBJ}));
Adriana Kobylakb8cb0cc2019-05-31 09:58:04 -0500217
218 std::map<std::string, std::vector<std::string>> mapperResponse;
219
220 try
221 {
222 auto mapperResponseMsg = bus.call(mapperCall);
223 mapperResponseMsg.read(mapperResponse);
224 if (mapperResponse.empty())
225 {
226 log<level::ERR>("Invalid Response from mapper");
227 elog<InternalFailure>();
228 }
229 }
230 catch (const sdbusplus::exception::SdBusError& e)
Eddie James13fc66a2017-08-31 15:36:44 -0500231 {
232 log<level::ERR>("Error in Mapper call");
233 elog<InternalFailure>();
234 }
Eddie James13fc66a2017-08-31 15:36:44 -0500235
236 auto method = bus.new_method_call((mapperResponse.begin()->first).c_str(),
237 CHASSIS_STATE_PATH,
Adriana Kobylak70dcb632018-02-27 15:46:52 -0600238 SYSTEMD_PROPERTY_INTERFACE, "Get");
Eddie James13fc66a2017-08-31 15:36:44 -0500239 method.append(CHASSIS_STATE_OBJ, "CurrentPowerState");
Adriana Kobylakb8cb0cc2019-05-31 09:58:04 -0500240
241 sdbusplus::message::variant<std::string> currentChassisState;
242
243 try
244 {
245 auto response = bus.call(method);
246 response.read(currentChassisState);
247 auto strParam = sdbusplus::message::variant_ns::get<std::string>(
248 currentChassisState);
249 return (strParam != CHASSIS_STATE_OFF);
250 }
251 catch (const sdbusplus::exception::SdBusError& e)
Eddie James13fc66a2017-08-31 15:36:44 -0500252 {
253 log<level::ERR>("Error in fetching current Chassis State",
Gunnar Mills850d5f62017-10-19 17:04:38 -0500254 entry("MAPPERRESPONSE=%s",
Eddie James13fc66a2017-08-31 15:36:44 -0500255 (mapperResponse.begin()->first).c_str()));
256 elog<InternalFailure>();
257 }
Eddie James13fc66a2017-08-31 15:36:44 -0500258}
259
Adriana Kobylakbefe5ce2017-04-05 15:57:44 -0500260} // namespace updater
Adriana Kobylak2d8fa222017-03-15 12:34:32 -0500261} // namespace software
262} // namespace openpower