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 7a9ac9279SLei YU #include <filesystem> 8f6ed5897SGunnar Mills #include <phosphor-logging/elog-errors.hpp> 9f6ed5897SGunnar Mills #include <phosphor-logging/log.hpp> 102d8fa225SAdriana Kobylak 112d8fa225SAdriana Kobylak namespace openpower 122d8fa225SAdriana Kobylak { 132d8fa225SAdriana Kobylak namespace software 142d8fa225SAdriana Kobylak { 15befe5ce4SAdriana Kobylak namespace updater 162d8fa225SAdriana Kobylak { 17a9ac9279SLei YU namespace server = sdbusplus::xyz::openbmc_project::Software::server; 18a9ac9279SLei YU namespace fs = std::filesystem; 19a9ac9279SLei YU 2013fc66adSEddie James using namespace sdbusplus::xyz::openbmc_project::Common::Error; 21b66ac3aeSAdriana Kobylak using namespace phosphor::logging; 22b66ac3aeSAdriana Kobylak 23a9ac9279SLei YU void ItemUpdater::createActivation(sdbusplus::message::message& m) 24a9ac9279SLei YU { 25a9ac9279SLei YU using SVersion = server::Version; 26a9ac9279SLei YU using VersionPurpose = SVersion::VersionPurpose; 27a9ac9279SLei YU 28a9ac9279SLei YU sdbusplus::message::object_path objPath; 29*573552aeSPatrick Williams std::map<std::string, std::map<std::string, std::variant<std::string>>> 30a9ac9279SLei YU interfaces; 31a9ac9279SLei YU m.read(objPath, interfaces); 32a9ac9279SLei YU 33a9ac9279SLei YU std::string path(std::move(objPath)); 34a9ac9279SLei YU std::string filePath; 35a9ac9279SLei YU auto purpose = VersionPurpose::Unknown; 36a9ac9279SLei YU std::string version; 37a9ac9279SLei YU 38a9ac9279SLei YU for (const auto& intf : interfaces) 39a9ac9279SLei YU { 40a9ac9279SLei YU if (intf.first == VERSION_IFACE) 41a9ac9279SLei YU { 42a9ac9279SLei YU for (const auto& property : intf.second) 43a9ac9279SLei YU { 44a9ac9279SLei YU if (property.first == "Purpose") 45a9ac9279SLei YU { 46a9ac9279SLei YU // Only process the Host and System images 47a9ac9279SLei YU auto value = SVersion::convertVersionPurposeFromString( 48550f31b3SPatrick Williams std::get<std::string>(property.second)); 49a9ac9279SLei YU 50a9ac9279SLei YU if (value == VersionPurpose::Host || 51a9ac9279SLei YU value == VersionPurpose::System) 52a9ac9279SLei YU { 53a9ac9279SLei YU purpose = value; 54a9ac9279SLei YU } 55a9ac9279SLei YU } 56a9ac9279SLei YU else if (property.first == "Version") 57a9ac9279SLei YU { 58550f31b3SPatrick Williams version = std::get<std::string>(property.second); 59a9ac9279SLei YU } 60a9ac9279SLei YU } 61a9ac9279SLei YU } 62a9ac9279SLei YU else if (intf.first == FILEPATH_IFACE) 63a9ac9279SLei YU { 64a9ac9279SLei YU for (const auto& property : intf.second) 65a9ac9279SLei YU { 66a9ac9279SLei YU if (property.first == "Path") 67a9ac9279SLei YU { 68550f31b3SPatrick Williams filePath = std::get<std::string>(property.second); 69a9ac9279SLei YU } 70a9ac9279SLei YU } 71a9ac9279SLei YU } 72a9ac9279SLei YU } 73a9ac9279SLei YU if ((filePath.empty()) || (purpose == VersionPurpose::Unknown)) 74a9ac9279SLei YU { 75a9ac9279SLei YU return; 76a9ac9279SLei YU } 77a9ac9279SLei YU 78a9ac9279SLei YU // Version id is the last item in the path 79a9ac9279SLei YU auto pos = path.rfind("/"); 80a9ac9279SLei YU if (pos == std::string::npos) 81a9ac9279SLei YU { 82a9ac9279SLei YU log<level::ERR>("No version id found in object path", 83a9ac9279SLei YU entry("OBJPATH=%s", path.c_str())); 84a9ac9279SLei YU return; 85a9ac9279SLei YU } 86a9ac9279SLei YU 87a9ac9279SLei YU auto versionId = path.substr(pos + 1); 88a9ac9279SLei YU 89a9ac9279SLei YU if (activations.find(versionId) == activations.end()) 90a9ac9279SLei YU { 91a9ac9279SLei YU // Determine the Activation state by processing the given image dir. 92a9ac9279SLei YU auto activationState = server::Activation::Activations::Invalid; 93a9ac9279SLei YU AssociationList associations = {}; 94a9ac9279SLei YU if (validateImage(filePath)) 95a9ac9279SLei YU { 96a9ac9279SLei YU activationState = server::Activation::Activations::Ready; 97a9ac9279SLei YU // Create an association to the host inventory item 98a9ac9279SLei YU associations.emplace_back(std::make_tuple( 99a9ac9279SLei YU ACTIVATION_FWD_ASSOCIATION, ACTIVATION_REV_ASSOCIATION, 100a9ac9279SLei YU HOST_INVENTORY_PATH)); 101a9ac9279SLei YU } 102a9ac9279SLei YU 103a9ac9279SLei YU fs::path manifestPath(filePath); 104a9ac9279SLei YU manifestPath /= MANIFEST_FILE; 105a9ac9279SLei YU std::string extendedVersion = 106a9ac9279SLei YU (Version::getValue( 107a9ac9279SLei YU manifestPath.string(), 108a9ac9279SLei YU std::map<std::string, std::string>{{"extended_version", ""}})) 109a9ac9279SLei YU .begin() 110a9ac9279SLei YU ->second; 111a9ac9279SLei YU 112a9ac9279SLei YU auto activation = createActivationObject( 113a9ac9279SLei YU path, versionId, extendedVersion, activationState, associations); 114a9ac9279SLei YU activations.emplace(versionId, std::move(activation)); 115a9ac9279SLei YU 116a9ac9279SLei YU auto versionPtr = 117a9ac9279SLei YU createVersionObject(path, versionId, version, purpose, filePath); 118a9ac9279SLei YU versions.emplace(versionId, std::move(versionPtr)); 119a9ac9279SLei YU } 120a9ac9279SLei YU return; 121a9ac9279SLei YU } 122a9ac9279SLei YU 123f3ce4337SLei YU void ItemUpdater::createActiveAssociation(const std::string& path) 1242d8fa225SAdriana Kobylak { 125f3ce4337SLei YU assocs.emplace_back( 126f3ce4337SLei YU std::make_tuple(ACTIVE_FWD_ASSOCIATION, ACTIVE_REV_ASSOCIATION, path)); 127f3ce4337SLei YU associations(assocs); 128b66ac3aeSAdriana Kobylak } 129b66ac3aeSAdriana Kobylak 130f3ce4337SLei YU void ItemUpdater::updateFunctionalAssociation(const std::string& versionId) 131b66ac3aeSAdriana Kobylak { 132f3ce4337SLei YU std::string path = std::string{SOFTWARE_OBJPATH} + '/' + versionId; 133f3ce4337SLei YU // remove all functional associations 134f3ce4337SLei YU for (auto iter = assocs.begin(); iter != assocs.end();) 1352fdb9310SAdriana Kobylak { 136f3ce4337SLei YU if ((std::get<0>(*iter)).compare(FUNCTIONAL_FWD_ASSOCIATION) == 0) 137a8ade7e4SSaqib Khan { 138f3ce4337SLei YU iter = assocs.erase(iter); 139a8ade7e4SSaqib Khan } 140a8ade7e4SSaqib Khan else 141a8ade7e4SSaqib Khan { 142f3ce4337SLei YU ++iter; 143a8ade7e4SSaqib Khan } 144a8ade7e4SSaqib Khan } 145f3ce4337SLei YU assocs.emplace_back(std::make_tuple(FUNCTIONAL_FWD_ASSOCIATION, 146f3ce4337SLei YU FUNCTIONAL_REV_ASSOCIATION, path)); 147f3ce4337SLei YU associations(assocs); 1489c8adfa3SLeonel Gonzalez } 1499c8adfa3SLeonel Gonzalez 150f3ce4337SLei YU void ItemUpdater::removeAssociation(const std::string& path) 151dd961b6cSMichael Tritz { 152f3ce4337SLei YU for (auto iter = assocs.begin(); iter != assocs.end();) 153f3ce4337SLei YU { 154f3ce4337SLei YU if ((std::get<2>(*iter)).compare(path) == 0) 155f3ce4337SLei YU { 156f3ce4337SLei YU iter = assocs.erase(iter); 157f3ce4337SLei YU associations(assocs); 158dd961b6cSMichael Tritz } 159f3ce4337SLei YU else 1609c8adfa3SLeonel Gonzalez { 161f3ce4337SLei YU ++iter; 162dd961b6cSMichael Tritz } 1639c8adfa3SLeonel Gonzalez } 164ca9ba069SAdriana Kobylak } 165ca9ba069SAdriana Kobylak 166f3ce4337SLei YU bool ItemUpdater::erase(std::string entryId) 167fa7aa12cSMichael Tritz { 168f3ce4337SLei YU if (isVersionFunctional(entryId) && isChassisOn()) 169ca9ba069SAdriana Kobylak { 170f3ce4337SLei YU log<level::ERR>(("Error: Version " + entryId + 171f3ce4337SLei YU " is currently active and running on the host." 172f3ce4337SLei YU " Unable to remove.") 173f3ce4337SLei YU .c_str()); 17413fc66adSEddie James return false; 17513fc66adSEddie James } 17613fc66adSEddie James 177f3ce4337SLei YU // Removing entry in versions map 178f3ce4337SLei YU auto it = versions.find(entryId); 179f3ce4337SLei YU if (it == versions.end()) 18013fc66adSEddie James { 181f3ce4337SLei YU log<level::ERR>(("Error: Failed to find version " + entryId + 182f3ce4337SLei YU " in item updater versions map." 183f3ce4337SLei YU " Unable to remove.") 184f3ce4337SLei YU .c_str()); 185f3ce4337SLei YU } 186f3ce4337SLei YU else 187f3ce4337SLei YU { 188f3ce4337SLei YU versions.erase(entryId); 18913fc66adSEddie James } 19013fc66adSEddie James 191f3ce4337SLei YU // Removing entry in activations map 192f3ce4337SLei YU auto ita = activations.find(entryId); 193f3ce4337SLei YU if (ita == activations.end()) 19413fc66adSEddie James { 195f3ce4337SLei YU log<level::ERR>(("Error: Failed to find version " + entryId + 196f3ce4337SLei YU " in item updater activations map." 197f3ce4337SLei YU " Unable to remove.") 198f3ce4337SLei YU .c_str()); 19913fc66adSEddie James } 200f3ce4337SLei YU else 201f3ce4337SLei YU { 202f3ce4337SLei YU removeAssociation(ita->second->path); 203f3ce4337SLei YU activations.erase(entryId); 204f3ce4337SLei YU } 20513fc66adSEddie James return true; 20613fc66adSEddie James } 20713fc66adSEddie James 20813fc66adSEddie James bool ItemUpdater::isChassisOn() 20913fc66adSEddie James { 21070dcb63aSAdriana Kobylak auto mapperCall = bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH, 21170dcb63aSAdriana Kobylak MAPPER_INTERFACE, "GetObject"); 21213fc66adSEddie James 21313fc66adSEddie James mapperCall.append(CHASSIS_STATE_PATH, 21413fc66adSEddie James std::vector<std::string>({CHASSIS_STATE_OBJ})); 215b8cb0cc9SAdriana Kobylak 216b8cb0cc9SAdriana Kobylak std::map<std::string, std::vector<std::string>> mapperResponse; 217b8cb0cc9SAdriana Kobylak 218b8cb0cc9SAdriana Kobylak try 21913fc66adSEddie James { 220b8cb0cc9SAdriana Kobylak auto mapperResponseMsg = bus.call(mapperCall); 22113fc66adSEddie James mapperResponseMsg.read(mapperResponse); 22213fc66adSEddie James if (mapperResponse.empty()) 22313fc66adSEddie James { 22413fc66adSEddie James log<level::ERR>("Invalid Response from mapper"); 22513fc66adSEddie James elog<InternalFailure>(); 22613fc66adSEddie James } 227b8cb0cc9SAdriana Kobylak } 228b8cb0cc9SAdriana Kobylak catch (const sdbusplus::exception::SdBusError& e) 229b8cb0cc9SAdriana Kobylak { 230b8cb0cc9SAdriana Kobylak log<level::ERR>("Error in Mapper call"); 231b8cb0cc9SAdriana Kobylak elog<InternalFailure>(); 232b8cb0cc9SAdriana Kobylak } 23313fc66adSEddie James 23413fc66adSEddie James auto method = bus.new_method_call((mapperResponse.begin()->first).c_str(), 23513fc66adSEddie James CHASSIS_STATE_PATH, 23670dcb63aSAdriana Kobylak SYSTEMD_PROPERTY_INTERFACE, "Get"); 23713fc66adSEddie James method.append(CHASSIS_STATE_OBJ, "CurrentPowerState"); 238b8cb0cc9SAdriana Kobylak 239212102e6SPatrick Williams std::variant<std::string> currentChassisState; 240b8cb0cc9SAdriana Kobylak 241b8cb0cc9SAdriana Kobylak try 242b8cb0cc9SAdriana Kobylak { 24313fc66adSEddie James auto response = bus.call(method); 244b8cb0cc9SAdriana Kobylak response.read(currentChassisState); 245550f31b3SPatrick Williams auto strParam = std::get<std::string>(currentChassisState); 246b8cb0cc9SAdriana Kobylak return (strParam != CHASSIS_STATE_OFF); 247b8cb0cc9SAdriana Kobylak } 248b8cb0cc9SAdriana Kobylak catch (const sdbusplus::exception::SdBusError& e) 24913fc66adSEddie James { 25013fc66adSEddie James log<level::ERR>("Error in fetching current Chassis State", 251850d5f6bSGunnar Mills entry("MAPPERRESPONSE=%s", 25213fc66adSEddie James (mapperResponse.begin()->first).c_str())); 25313fc66adSEddie James elog<InternalFailure>(); 25413fc66adSEddie James } 25513fc66adSEddie James } 25613fc66adSEddie James 257befe5ce4SAdriana Kobylak } // namespace updater 2582d8fa225SAdriana Kobylak } // namespace software 2592d8fa225SAdriana Kobylak } // namespace openpower 260