blob: d25c04a14f0536f6c97c41d23d2570e67016d068 [file] [log] [blame]
Matthew Barth11547c92020-05-05 10:34:27 -05001/**
2 * Copyright © 2020 IBM Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16#pragma once
17
18#include "sdbusplus.hpp"
19
20#include <nlohmann/json.hpp>
21#include <phosphor-logging/log.hpp>
22#include <sdbusplus/bus.hpp>
23#include <sdeventplus/source/signal.hpp>
24
25#include <filesystem>
26#include <fstream>
27
28namespace phosphor::fan
29{
30
31namespace fs = std::filesystem;
32using json = nlohmann::json;
33using namespace phosphor::logging;
34
35constexpr auto confOverridePath = "/etc/phosphor-fan-presence";
36constexpr auto confBasePath = "/usr/share/phosphor-fan-presence";
37constexpr auto confDbusPath = "/xyz/openbmc_project/inventory/system/chassis";
38constexpr auto confDbusIntf =
39 "xyz.openbmc_project.Inventory.Decorator.Compatible";
40constexpr auto confDbusProp = "Names";
41
42class JsonConfig
43{
44 public:
45 /**
46 * Get the json configuration file. The first location found to contain
47 * the json config file for the given fan application is used from the
48 * following locations in order.
49 * 1.) From the confOverridePath location
50 * 2.) From config file found using a property value as a relative
51 * path extension on the base path from the dbus object where:
52 * path = Path set in confDbusPath
53 * interface = Interface set in confDbusIntf
54 * property = Property set in confDbusProp
55 * 3.) *DEFAULT* - From the confBasePath location
56 *
57 * @brief Get the configuration file to be used
58 *
59 * @param[in] bus - The dbus bus object
60 * @param[in] appName - The phosphor-fan-presence application name
61 * @param[in] fileName - Application's configuration file's name
62 *
63 * @return filesystem path
64 * The filesystem path to the configuration file to use
65 */
66 static const fs::path getConfFile(sdbusplus::bus::bus& bus,
67 const std::string& appName,
68 const std::string& fileName)
69 {
70 // Check override location
71 fs::path confFile = fs::path{confOverridePath} / appName / fileName;
72 if (fs::exists(confFile))
73 {
74 return confFile;
75 }
76
77 try
78 {
79 // Retrieve json config relative path location from dbus
80 auto confDbusValue =
81 util::SDBusPlus::getProperty<std::vector<std::string>>(
82 bus, confDbusPath, confDbusIntf, confDbusProp);
83 // Look for a config file at each entry relative to the base
84 // path and use the first one found
85 auto it = std::find_if(
86 confDbusValue.begin(), confDbusValue.end(),
87 [&confFile, &appName, &fileName](auto const& entry) {
88 confFile =
89 fs::path{confBasePath} / appName / entry / fileName;
90 return fs::exists(confFile);
91 });
92 if (it == confDbusValue.end())
93 {
94 // Property exists, but no config file found. Use default base
95 // path
96 confFile = fs::path{confBasePath} / appName / fileName;
97 }
98 }
99 catch (const util::DBusError&)
100 {
101 // Property unavailable, attempt default base path
102 confFile = fs::path{confBasePath} / appName / fileName;
103 }
104
105 if (!fs::exists(confFile))
106 {
107 log<level::ERR>("No JSON config file found",
108 entry("DEFAULT_FILE=%s", confFile.c_str()));
109 throw std::runtime_error("No JSON config file found");
110 }
111
112 return confFile;
113 }
114
115 /**
116 * @brief Load the JSON config file
117 *
118 * @param[in] confFile - File system path of the configuration file to load
119 *
120 * @return Parsed JSON object
121 * The parsed JSON configuration file object
122 */
123 static const json load(const fs::path& confFile)
124 {
125 std::ifstream file;
126 json jsonConf;
127
128 if (fs::exists(confFile))
129 {
Matthew Barthd06905c2020-06-12 08:13:06 -0500130 log<level::INFO>("Loading configuration",
131 entry("JSON_FILE=%s", confFile.c_str()));
Matthew Barth11547c92020-05-05 10:34:27 -0500132 file.open(confFile);
133 try
134 {
135 jsonConf = json::parse(file);
136 }
137 catch (std::exception& e)
138 {
139 log<level::ERR>("Failed to parse JSON config file",
140 entry("JSON_FILE=%s", confFile.c_str()),
141 entry("JSON_ERROR=%s", e.what()));
142 throw std::runtime_error("Failed to parse JSON config file");
143 }
144 }
145 else
146 {
147 log<level::ERR>("Unable to open JSON config file",
148 entry("JSON_FILE=%s", confFile.c_str()));
149 throw std::runtime_error("Unable to open JSON config file");
150 }
151
152 return jsonConf;
153 }
154};
155
156} // namespace phosphor::fan