11a568650SJolie Ku /** 21a568650SJolie Ku * Copyright © 2019 IBM Corporation 31a568650SJolie Ku * 41a568650SJolie Ku * Licensed under the Apache License, Version 2.0 (the "License"); 51a568650SJolie Ku * you may not use this file except in compliance with the License. 61a568650SJolie Ku * You may obtain a copy of the License at 71a568650SJolie Ku * 81a568650SJolie Ku * http://www.apache.org/licenses/LICENSE-2.0 91a568650SJolie Ku * 101a568650SJolie Ku * Unless required by applicable law or agreed to in writing, software 111a568650SJolie Ku * distributed under the License is distributed on an "AS IS" BASIS, 121a568650SJolie Ku * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 131a568650SJolie Ku * See the License for the specific language governing permissions and 141a568650SJolie Ku * limitations under the License. 151a568650SJolie Ku */ 161a568650SJolie Ku #include "json_parser.hpp" 171a568650SJolie Ku 181a568650SJolie Ku #include "anyof.hpp" 191a568650SJolie Ku #include "fallback.hpp" 201a568650SJolie Ku #include "gpio.hpp" 211a568650SJolie Ku #include "json_config.hpp" 221a568650SJolie Ku #include "sdbusplus.hpp" 231a568650SJolie Ku #include "tach.hpp" 241a568650SJolie Ku 251a568650SJolie Ku #include <nlohmann/json.hpp> 261a568650SJolie Ku #include <phosphor-logging/log.hpp> 271a568650SJolie Ku #include <sdbusplus/bus.hpp> 281a568650SJolie Ku 291a568650SJolie Ku #include <filesystem> 301a568650SJolie Ku #include <fstream> 311a568650SJolie Ku #include <string> 321a568650SJolie Ku 331a568650SJolie Ku namespace phosphor 341a568650SJolie Ku { 351a568650SJolie Ku namespace fan 361a568650SJolie Ku { 371a568650SJolie Ku namespace presence 381a568650SJolie Ku { 391a568650SJolie Ku 401a568650SJolie Ku using json = nlohmann::json; 411a568650SJolie Ku namespace fs = std::filesystem; 421a568650SJolie Ku using namespace phosphor::logging; 431a568650SJolie Ku 441a568650SJolie Ku policies JsonConfig::_policies; 451a568650SJolie Ku const std::map<std::string, methodHandler> JsonConfig::_methods = { 461a568650SJolie Ku {"tach", method::getTach}, {"gpio", method::getGpio}}; 471a568650SJolie Ku const std::map<std::string, rpolicyHandler> JsonConfig::_rpolicies = { 481a568650SJolie Ku {"anyof", rpolicy::getAnyof}, {"fallback", rpolicy::getFallback}}; 491a568650SJolie Ku 501a568650SJolie Ku JsonConfig::JsonConfig(sdbusplus::bus::bus& bus) : _bus(bus) 51*0daedd18SMatt Spinler {} 521a568650SJolie Ku 53*0daedd18SMatt Spinler void JsonConfig::start(const std::string& confFile) 54*0daedd18SMatt Spinler { 55*0daedd18SMatt Spinler process(phosphor::fan::JsonConfig::load(confFile)); 56*0daedd18SMatt Spinler 57*0daedd18SMatt Spinler for (auto& p : _policies) 58*0daedd18SMatt Spinler { 59*0daedd18SMatt Spinler p->monitor(); 60*0daedd18SMatt Spinler } 611a568650SJolie Ku } 621a568650SJolie Ku 631a568650SJolie Ku const policies& JsonConfig::get() 641a568650SJolie Ku { 651a568650SJolie Ku return _policies; 661a568650SJolie Ku } 671a568650SJolie Ku 681a568650SJolie Ku void JsonConfig::sighupHandler(sdeventplus::source::Signal& sigSrc, 691a568650SJolie Ku const struct signalfd_siginfo* sigInfo) 701a568650SJolie Ku { 711a568650SJolie Ku try 721a568650SJolie Ku { 731a568650SJolie Ku using config = fan::JsonConfig; 741a568650SJolie Ku 759e9f599cSMatt Spinler _reporter.reset(); 769e9f599cSMatt Spinler 771a568650SJolie Ku // Load and process the json configuration 781a568650SJolie Ku process( 791a568650SJolie Ku config::load(config::getConfFile(_bus, confAppName, confFileName))); 801a568650SJolie Ku 811a568650SJolie Ku for (auto& p : _policies) 821a568650SJolie Ku { 831a568650SJolie Ku p->monitor(); 841a568650SJolie Ku } 851a568650SJolie Ku log<level::INFO>("Configuration loaded successfully"); 861a568650SJolie Ku } 871a568650SJolie Ku catch (std::runtime_error& re) 881a568650SJolie Ku { 891a568650SJolie Ku log<level::ERR>("Error loading config, no config changes made", 901a568650SJolie Ku entry("LOAD_ERROR=%s", re.what())); 911a568650SJolie Ku } 921a568650SJolie Ku } 931a568650SJolie Ku 941a568650SJolie Ku void JsonConfig::process(const json& jsonConf) 951a568650SJolie Ku { 961a568650SJolie Ku policies policies; 971a568650SJolie Ku std::vector<fanPolicy> fans; 981a568650SJolie Ku // Set the expected number of fan entries 991a568650SJolie Ku // to be size of the list of fan json config entries 1001a568650SJolie Ku // (Must be done to eliminate vector reallocation of fan references) 1019e9f599cSMatt Spinler fans.reserve(jsonConf.size()); 1029e9f599cSMatt Spinler for (auto& member : jsonConf) 1031a568650SJolie Ku { 1041a568650SJolie Ku if (!member.contains("name") || !member.contains("path") || 1051a568650SJolie Ku !member.contains("methods") || !member.contains("rpolicy")) 1061a568650SJolie Ku { 1071a568650SJolie Ku log<level::ERR>("Missing required fan presence properties", 1081a568650SJolie Ku entry("REQUIRED_PROPERTIES=%s", 1091a568650SJolie Ku "{name, path, methods, rpolicy}")); 1101a568650SJolie Ku throw std::runtime_error( 1111a568650SJolie Ku "Missing required fan presence properties"); 1121a568650SJolie Ku } 1131a568650SJolie Ku 1141a568650SJolie Ku // Loop thru the configured methods of presence detection 1151a568650SJolie Ku std::vector<std::unique_ptr<PresenceSensor>> sensors; 1161a568650SJolie Ku for (auto& method : member["methods"].items()) 1171a568650SJolie Ku { 1181a568650SJolie Ku if (!method.value().contains("type")) 1191a568650SJolie Ku { 1201a568650SJolie Ku log<level::ERR>( 1211a568650SJolie Ku "Missing required fan presence method type", 1221a568650SJolie Ku entry("FAN_NAME=%s", 1231a568650SJolie Ku member["name"].get<std::string>().c_str())); 1241a568650SJolie Ku throw std::runtime_error( 1251a568650SJolie Ku "Missing required fan presence method type"); 1261a568650SJolie Ku } 1271a568650SJolie Ku // The method type of fan presence detection 1281a568650SJolie Ku // (Must have a supported function within the method namespace) 1291a568650SJolie Ku auto type = method.value()["type"].get<std::string>(); 1301a568650SJolie Ku std::transform(type.begin(), type.end(), type.begin(), tolower); 1311a568650SJolie Ku auto func = _methods.find(type); 1321a568650SJolie Ku if (func != _methods.end()) 1331a568650SJolie Ku { 1341a568650SJolie Ku // Call function for method type 1351a568650SJolie Ku auto sensor = func->second(fans.size(), method.value()); 1361a568650SJolie Ku if (sensor) 1371a568650SJolie Ku { 1381a568650SJolie Ku sensors.emplace_back(std::move(sensor)); 1391a568650SJolie Ku } 1401a568650SJolie Ku } 1411a568650SJolie Ku else 1421a568650SJolie Ku { 1431a568650SJolie Ku log<level::ERR>( 1441a568650SJolie Ku "Invalid fan presence method type", 1451a568650SJolie Ku entry("FAN_NAME=%s", 1461a568650SJolie Ku member["name"].get<std::string>().c_str()), 1471a568650SJolie Ku entry("METHOD_TYPE=%s", type.c_str())); 1481a568650SJolie Ku throw std::runtime_error("Invalid fan presence method type"); 1491a568650SJolie Ku } 1501a568650SJolie Ku } 1519e9f599cSMatt Spinler 1529e9f599cSMatt Spinler // Get the amount of time a fan must be not present before 1539e9f599cSMatt Spinler // creating an error. 1549e9f599cSMatt Spinler std::optional<size_t> timeUntilError; 1559e9f599cSMatt Spinler if (member.contains("fan_missing_error_time")) 1569e9f599cSMatt Spinler { 1579e9f599cSMatt Spinler timeUntilError = member["fan_missing_error_time"].get<size_t>(); 1589e9f599cSMatt Spinler } 1599e9f599cSMatt Spinler 1609e9f599cSMatt Spinler auto fan = 1619e9f599cSMatt Spinler std::make_tuple(member["name"], member["path"], timeUntilError); 1621a568650SJolie Ku // Create a fan object 1631a568650SJolie Ku fans.emplace_back(std::make_tuple(fan, std::move(sensors))); 1641a568650SJolie Ku 1651a568650SJolie Ku // Add fan presence policy 1661a568650SJolie Ku auto policy = getPolicy(member["rpolicy"], fans.back()); 1671a568650SJolie Ku if (policy) 1681a568650SJolie Ku { 1691a568650SJolie Ku policies.emplace_back(std::move(policy)); 1701a568650SJolie Ku } 1711a568650SJolie Ku } 1721a568650SJolie Ku 1731a568650SJolie Ku // Success, refresh fans and policies lists 1741a568650SJolie Ku _fans.clear(); 1751a568650SJolie Ku _fans.swap(fans); 1761a568650SJolie Ku 1771a568650SJolie Ku _policies.clear(); 1781a568650SJolie Ku _policies.swap(policies); 179e8122390SMatt Spinler 180e8122390SMatt Spinler // Create the error reporter class if necessary 1819e9f599cSMatt Spinler if (std::any_of(_fans.begin(), _fans.end(), [](const auto& fan) { 1829e9f599cSMatt Spinler return std::get<std::optional<size_t>>(std::get<Fan>(fan)) != 1839e9f599cSMatt Spinler std::nullopt; 1849e9f599cSMatt Spinler })) 185e8122390SMatt Spinler { 1869e9f599cSMatt Spinler _reporter = std::make_unique<ErrorReporter>(_bus, _fans); 187e8122390SMatt Spinler } 1881a568650SJolie Ku } 1891a568650SJolie Ku 1901a568650SJolie Ku std::unique_ptr<RedundancyPolicy> 1911a568650SJolie Ku JsonConfig::getPolicy(const json& rpolicy, const fanPolicy& fpolicy) 1921a568650SJolie Ku { 1931a568650SJolie Ku if (!rpolicy.contains("type")) 1941a568650SJolie Ku { 1951a568650SJolie Ku log<level::ERR>( 1961a568650SJolie Ku "Missing required fan presence policy type", 1971a568650SJolie Ku entry("FAN_NAME=%s", 1981a568650SJolie Ku std::get<fanPolicyFanPos>(std::get<Fan>(fpolicy)).c_str()), 1991a568650SJolie Ku entry("REQUIRED_PROPERTIES=%s", "{type}")); 2001a568650SJolie Ku throw std::runtime_error("Missing required fan presence policy type"); 2011a568650SJolie Ku } 2021a568650SJolie Ku 2031a568650SJolie Ku // The redundancy policy type for fan presence detection 2041a568650SJolie Ku // (Must have a supported function within the rpolicy namespace) 2051a568650SJolie Ku auto type = rpolicy["type"].get<std::string>(); 2061a568650SJolie Ku std::transform(type.begin(), type.end(), type.begin(), tolower); 2071a568650SJolie Ku auto func = _rpolicies.find(type); 2081a568650SJolie Ku if (func != _rpolicies.end()) 2091a568650SJolie Ku { 2101a568650SJolie Ku // Call function for redundancy policy type and return the policy 2111a568650SJolie Ku return func->second(fpolicy); 2121a568650SJolie Ku } 2131a568650SJolie Ku else 2141a568650SJolie Ku { 2151a568650SJolie Ku log<level::ERR>( 2161a568650SJolie Ku "Invalid fan presence policy type", 2171a568650SJolie Ku entry("FAN_NAME=%s", 2181a568650SJolie Ku std::get<fanPolicyFanPos>(std::get<Fan>(fpolicy)).c_str()), 2191a568650SJolie Ku entry("RPOLICY_TYPE=%s", type.c_str())); 2201a568650SJolie Ku throw std::runtime_error("Invalid fan presence methods policy type"); 2211a568650SJolie Ku } 2221a568650SJolie Ku } 2231a568650SJolie Ku 2241a568650SJolie Ku /** 2251a568650SJolie Ku * Methods of fan presence detection function definitions 2261a568650SJolie Ku */ 2271a568650SJolie Ku namespace method 2281a568650SJolie Ku { 2291a568650SJolie Ku // Get a constructed presence sensor for fan presence detection by tach 2301a568650SJolie Ku std::unique_ptr<PresenceSensor> getTach(size_t fanIndex, const json& method) 2311a568650SJolie Ku { 2321a568650SJolie Ku if (!method.contains("sensors") || method["sensors"].size() == 0) 2331a568650SJolie Ku { 2341a568650SJolie Ku log<level::ERR>("Missing required tach method properties", 2351a568650SJolie Ku entry("FAN_ENTRY=%d", fanIndex), 2361a568650SJolie Ku entry("REQUIRED_PROPERTIES=%s", "{sensors}")); 2371a568650SJolie Ku throw std::runtime_error("Missing required tach method properties"); 2381a568650SJolie Ku } 2391a568650SJolie Ku 2401a568650SJolie Ku std::vector<std::string> sensors; 2411a568650SJolie Ku for (auto& sensor : method["sensors"]) 2421a568650SJolie Ku { 2431a568650SJolie Ku sensors.emplace_back(sensor.get<std::string>()); 2441a568650SJolie Ku } 2451a568650SJolie Ku 2461a568650SJolie Ku return std::make_unique<PolicyAccess<Tach, JsonConfig>>(fanIndex, 2471a568650SJolie Ku std::move(sensors)); 2481a568650SJolie Ku } 2491a568650SJolie Ku 2501a568650SJolie Ku // Get a constructed presence sensor for fan presence detection by gpio 2511a568650SJolie Ku std::unique_ptr<PresenceSensor> getGpio(size_t fanIndex, const json& method) 2521a568650SJolie Ku { 2531a568650SJolie Ku if (!method.contains("physpath") || !method.contains("devpath") || 2541a568650SJolie Ku !method.contains("key")) 2551a568650SJolie Ku { 2561a568650SJolie Ku log<level::ERR>( 2571a568650SJolie Ku "Missing required gpio method properties", 2581a568650SJolie Ku entry("FAN_ENTRY=%d", fanIndex), 2591a568650SJolie Ku entry("REQUIRED_PROPERTIES=%s", "{physpath, devpath, key}")); 2601a568650SJolie Ku throw std::runtime_error("Missing required gpio method properties"); 2611a568650SJolie Ku } 2621a568650SJolie Ku 2631a568650SJolie Ku auto physpath = method["physpath"].get<std::string>(); 2641a568650SJolie Ku auto devpath = method["devpath"].get<std::string>(); 2651a568650SJolie Ku auto key = method["key"].get<unsigned int>(); 2661a568650SJolie Ku 2671a568650SJolie Ku return std::make_unique<PolicyAccess<Gpio, JsonConfig>>(fanIndex, physpath, 2681a568650SJolie Ku devpath, key); 2691a568650SJolie Ku } 2701a568650SJolie Ku 2711a568650SJolie Ku } // namespace method 2721a568650SJolie Ku 2731a568650SJolie Ku /** 2741a568650SJolie Ku * Redundancy policies for fan presence detection function definitions 2751a568650SJolie Ku */ 2761a568650SJolie Ku namespace rpolicy 2771a568650SJolie Ku { 2781a568650SJolie Ku // Get an `Anyof` redundancy policy for the fan 2791a568650SJolie Ku std::unique_ptr<RedundancyPolicy> getAnyof(const fanPolicy& fan) 2801a568650SJolie Ku { 2811a568650SJolie Ku std::vector<std::reference_wrapper<PresenceSensor>> pSensors; 2821a568650SJolie Ku for (auto& fanSensor : std::get<fanPolicySensorListPos>(fan)) 2831a568650SJolie Ku { 2841a568650SJolie Ku pSensors.emplace_back(*fanSensor); 2851a568650SJolie Ku } 2861a568650SJolie Ku 2871a568650SJolie Ku return std::make_unique<AnyOf>(std::get<fanPolicyFanPos>(fan), pSensors); 2881a568650SJolie Ku } 2891a568650SJolie Ku 2901a568650SJolie Ku // Get a `Fallback` redundancy policy for the fan 2911a568650SJolie Ku std::unique_ptr<RedundancyPolicy> getFallback(const fanPolicy& fan) 2921a568650SJolie Ku { 2931a568650SJolie Ku std::vector<std::reference_wrapper<PresenceSensor>> pSensors; 2941a568650SJolie Ku for (auto& fanSensor : std::get<fanPolicySensorListPos>(fan)) 2951a568650SJolie Ku { 2961a568650SJolie Ku // Place in the order given to fallback correctly 2971a568650SJolie Ku pSensors.emplace_back(*fanSensor); 2981a568650SJolie Ku } 2991a568650SJolie Ku 3001a568650SJolie Ku return std::make_unique<Fallback>(std::get<fanPolicyFanPos>(fan), pSensors); 3011a568650SJolie Ku } 3021a568650SJolie Ku 3031a568650SJolie Ku } // namespace rpolicy 3041a568650SJolie Ku 3051a568650SJolie Ku } // namespace presence 3061a568650SJolie Ku } // namespace fan 3071a568650SJolie Ku } // namespace phosphor 308