blob: 049478a4d3a2517f835e9b232885175015facc79 [file] [log] [blame]
#include "tlbmc/metrics/bmc_static_metrics.h"
#include <sys/sysinfo.h>
#include <systemd/sd-id128.h>
#include <array>
#include <cstdint>
#include <filesystem> // NOLINT
#include <fstream>
#include <memory>
#include <string>
#include <string_view>
#include <system_error> // NOLINT
#include "absl/memory/memory.h"
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/str_cat.h"
#include "g3/macros.h"
#include "openssl/sha.h"
namespace milotic_tlbmc {
constexpr std::string_view kOsReleasePath = "/etc/os-release";
constexpr std::string_view kBmcFirmwareVersionKey = "VERSION_ID=";
constexpr std::string_view kBmcRofsFlashIdPath = "/run/media";
absl::StatusOr<std::string> BmcStaticMetrics::FetchBmcFirmwareVersion(
std::string_view root_path) {
std::error_code ec;
if (!std::filesystem::exists(
std::filesystem::path(absl::StrCat(root_path, kOsReleasePath)), ec)) {
return absl::InternalError("/etc/os-release does not exist");
}
std::ifstream os_release_stream(absl::StrCat(root_path, kOsReleasePath));
if (!os_release_stream.good()) {
return absl::InternalError("Failed to open /etc/os-release.");
}
while (os_release_stream.good()) {
std::string line;
std::getline(os_release_stream, line);
if (line.starts_with(kBmcFirmwareVersionKey)) {
return line.substr(kBmcFirmwareVersionKey.length());
}
}
return absl::InternalError("Failed to find VERSION_ID in /etc/os-release.");
}
absl::StatusOr<std::string> BmcStaticMetrics::FetchBmcFirmwareFlashId(
std::string_view root_path) {
std::error_code bmc_rofs_flash_id_dir_exists_ec;
if (!std::filesystem::exists(
std::filesystem::path(absl::StrCat(root_path, kBmcRofsFlashIdPath)),
bmc_rofs_flash_id_dir_exists_ec)) {
return absl::InternalError("/run/media does not exist");
}
std::error_code bmc_rofs_flash_id_dir_iter_ec;
for (std::filesystem::directory_iterator dir_iter(
std::filesystem::path(absl::StrCat(root_path, kBmcRofsFlashIdPath)),
bmc_rofs_flash_id_dir_iter_ec);
dir_iter != std::filesystem::directory_iterator(); ++dir_iter) {
// Strip the rofs- prefix from the directory name to get the flash id.
if (dir_iter->is_directory() &&
dir_iter->path().filename().string().starts_with("rofs-")) {
return dir_iter->path().filename().string().substr(5);
}
}
return absl::InternalError(
"Failed to find BMC rofs firmware flash id under /run/media");
}
absl::StatusOr<std::string> BmcStaticMetrics::FetchBmcFirmwareVersionId(
std::string_view root_path, std::string_view bmc_firmware_version) {
ECCLESIA_ASSIGN_OR_RETURN(std::string bmc_firmware_flash_id,
FetchBmcFirmwareFlashId(root_path));
std::string version_to_hash =
absl::StrCat(bmc_firmware_version, bmc_firmware_flash_id);
// This code is to generate the BMC firmware version ID. The format is
// The logic is extracted from
// https://github.com/openbmc/phosphor-bmc-code-mgmt/blob/de331ae49afd6fe27271c4081ffa239746bda8b5/bmc/version.cpp#L104
std::array<uint8_t, SHA512_DIGEST_LENGTH> digest;
SHA512(reinterpret_cast<const uint8_t*>(version_to_hash.data()),
version_to_hash.size(), digest.data());
// We are only using the first 8 characters.
std::string version_id = absl::StrCat(absl::Hex(digest[0], absl::kZeroPad2),
absl::Hex(digest[1], absl::kZeroPad2),
absl::Hex(digest[2], absl::kZeroPad2),
absl::Hex(digest[3], absl::kZeroPad2));
return version_id;
}
absl::StatusOr<std::string> BmcStaticMetrics::FetchBmcUuid() {
std::string uuid;
// This ID needs to match the one in ipmid
sd_id128_t app_id{{0Xe0, 0Xe1, 0X73, 0X76, 0X64, 0X61, 0X47, 0Xda, 0Xa5, 0X0c,
0Xd0, 0Xcc, 0X64, 0X12, 0X45, 0X78}};
sd_id128_t machine_id{};
if (sd_id128_get_machine_app_specific(app_id, &machine_id) == 0) {
std::array<char, SD_ID128_STRING_MAX> str{};
uuid = sd_id128_to_string(machine_id, str.data());
uuid.insert(8, 1, '-');
uuid.insert(13, 1, '-');
uuid.insert(18, 1, '-');
uuid.insert(23, 1, '-');
}
return uuid;
}
absl::StatusOr<std::unique_ptr<BmcStaticMetrics>> BmcStaticMetrics::Create(
std::string_view root_path) {
ECCLESIA_ASSIGN_OR_RETURN(std::string bmc_firmware_version,
FetchBmcFirmwareVersion(root_path));
ECCLESIA_ASSIGN_OR_RETURN(
std::string bmc_firmware_version_id,
FetchBmcFirmwareVersionId(root_path, bmc_firmware_version));
ECCLESIA_ASSIGN_OR_RETURN(std::string bmc_uuid, FetchBmcUuid());
return absl::WrapUnique(new BmcStaticMetrics(
bmc_firmware_version, bmc_firmware_version_id, bmc_uuid));
}
std::string BmcStaticMetrics::GetBmcFirmwareVersion() const {
return bmc_firmware_version_;
}
std::string BmcStaticMetrics::GetBmcFirmwareVersionId() const {
return bmc_firmware_version_id_;
}
std::string BmcStaticMetrics::GetBmcUuid() const { return bmc_uuid_; }
} // namespace milotic_tlbmc