Tomáš Pecka | 292bc9c | 2021-01-11 22:03:11 +0100 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2021 CESNET, https://photonics.cesnet.cz/ |
| 3 | * |
| 4 | * Written by Tomáš Pecka <tomas.pecka@fit.cvut.cz> |
| 5 | * |
| 6 | */ |
| 7 | |
| 8 | #include <boost/algorithm/string/predicate.hpp> |
| 9 | #include <fstream> |
Tomáš Pecka | f976c5b | 2021-01-23 21:19:52 +0100 | [diff] [blame] | 10 | #include "IETFSystem.h" |
Tomáš Pecka | 879a603 | 2021-02-03 17:21:48 +0100 | [diff] [blame^] | 11 | #include "system_vars.h" |
| 12 | #include "utils/exec.h" |
Tomáš Pecka | 292bc9c | 2021-01-11 22:03:11 +0100 | [diff] [blame] | 13 | #include "utils/io.h" |
| 14 | #include "utils/log.h" |
Tomáš Pecka | 272abaf | 2021-01-24 12:28:43 +0100 | [diff] [blame] | 15 | #include "utils/sysrepo.h" |
Tomáš Pecka | 292bc9c | 2021-01-11 22:03:11 +0100 | [diff] [blame] | 16 | |
| 17 | using namespace std::literals; |
| 18 | |
| 19 | namespace { |
| 20 | |
| 21 | const auto IETF_SYSTEM_MODULE_NAME = "ietf-system"s; |
| 22 | const auto IETF_SYSTEM_STATE_MODULE_PREFIX = "/"s + IETF_SYSTEM_MODULE_NAME + ":system-state/"s; |
| 23 | |
| 24 | /** @brief Returns key=value pairs from (e.g. /etc/os-release) as a std::map */ |
| 25 | std::map<std::string, std::string> parseKeyValueFile(const std::filesystem::path& path) |
| 26 | { |
| 27 | std::map<std::string, std::string> res; |
| 28 | std::ifstream ifs(path); |
| 29 | if (!ifs.is_open()) |
| 30 | throw std::invalid_argument("File '" + std::string(path) + "' not found."); |
| 31 | |
| 32 | std::string line; |
| 33 | while (std::getline(ifs, line)) { |
| 34 | // man os-release: Lines beginning with "#" shall be ignored as comments. Blank lines are permitted and ignored. |
| 35 | if (line.empty() || boost::algorithm::starts_with(line, "#")) { |
| 36 | continue; |
| 37 | } |
| 38 | |
| 39 | size_t equalSignPos = line.find_first_of('='); |
| 40 | if (equalSignPos != std::string::npos) { |
| 41 | std::string key = line.substr(0, equalSignPos); |
| 42 | std::string val = line.substr(equalSignPos + 1); |
| 43 | |
| 44 | // remove quotes from value |
| 45 | if (val.length() >= 2 && val.front() == '"' && val.front() == val.back()) { |
| 46 | val = val.substr(1, val.length() - 2); |
| 47 | } |
| 48 | |
| 49 | res[key] = val; |
| 50 | } else { // when there is no = sign, treat the value as empty string |
| 51 | res[line] = ""; |
| 52 | } |
| 53 | } |
| 54 | |
| 55 | return res; |
| 56 | } |
| 57 | |
| 58 | } |
| 59 | |
| 60 | namespace velia::system { |
| 61 | |
| 62 | /** @brief Reads some OS-identification data from osRelease file and publishes them via ietf-system model */ |
Tomáš Pecka | f976c5b | 2021-01-23 21:19:52 +0100 | [diff] [blame] | 63 | IETFSystem::IETFSystem(std::shared_ptr<::sysrepo::Session> srSession, const std::filesystem::path& osRelease) |
Tomáš Pecka | 292bc9c | 2021-01-11 22:03:11 +0100 | [diff] [blame] | 64 | : m_srSession(std::move(srSession)) |
Tomáš Pecka | 879a603 | 2021-02-03 17:21:48 +0100 | [diff] [blame^] | 65 | , m_srSubscribe(std::make_shared<::sysrepo::Subscribe>(m_srSession)) |
Tomáš Pecka | 292bc9c | 2021-01-11 22:03:11 +0100 | [diff] [blame] | 66 | , m_log(spdlog::get("system")) |
| 67 | { |
| 68 | std::map<std::string, std::string> osReleaseContents = parseKeyValueFile(osRelease); |
| 69 | |
| 70 | std::map<std::string, std::string> opsSystemStateData { |
| 71 | {IETF_SYSTEM_STATE_MODULE_PREFIX + "platform/os-name", osReleaseContents.at("NAME")}, |
| 72 | {IETF_SYSTEM_STATE_MODULE_PREFIX + "platform/os-release", osReleaseContents.at("VERSION")}, |
| 73 | {IETF_SYSTEM_STATE_MODULE_PREFIX + "platform/os-version", osReleaseContents.at("VERSION")}, |
| 74 | }; |
| 75 | |
Tomáš Pecka | 272abaf | 2021-01-24 12:28:43 +0100 | [diff] [blame] | 76 | utils::valuesPush(opsSystemStateData, m_srSession, SR_DS_OPERATIONAL); |
Tomáš Pecka | 879a603 | 2021-02-03 17:21:48 +0100 | [diff] [blame^] | 77 | |
| 78 | m_srSubscribe->rpc_subscribe( |
| 79 | ("/" + IETF_SYSTEM_MODULE_NAME + ":system-restart").c_str(), |
| 80 | [this](::sysrepo::S_Session session, [[maybe_unused]] const char* op_path, [[maybe_unused]] const ::sysrepo::S_Vals input, [[maybe_unused]] sr_event_t event, [[maybe_unused]] uint32_t request_id, [[maybe_unused]] ::sysrepo::S_Vals_Holder output) { |
| 81 | try { |
| 82 | velia::utils::execAndWait(m_log, SYSTEMCTL_EXECUTABLE, {"reboot"}, "", {}); |
| 83 | } catch(const std::runtime_error& e) { |
| 84 | session->set_error("Reboot procedure failed.", nullptr); |
| 85 | return SR_ERR_OPERATION_FAILED; |
| 86 | } |
| 87 | |
| 88 | return SR_ERR_OK; |
| 89 | }, |
| 90 | 0, |
| 91 | SR_SUBSCR_CTX_REUSE); |
Tomáš Pecka | 292bc9c | 2021-01-11 22:03:11 +0100 | [diff] [blame] | 92 | } |
| 93 | } |