blob: 0c2721dd3bc0599419f8b38bee0b672a3c8d7c53 [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
Matthew Barth1826c732020-08-28 08:40:59 -050020#include <fmt/format.h>
21
Matthew Barth11547c92020-05-05 10:34:27 -050022#include <nlohmann/json.hpp>
23#include <phosphor-logging/log.hpp>
24#include <sdbusplus/bus.hpp>
25#include <sdeventplus/source/signal.hpp>
26
27#include <filesystem>
28#include <fstream>
29
30namespace phosphor::fan
31{
32
33namespace fs = std::filesystem;
34using json = nlohmann::json;
35using namespace phosphor::logging;
36
37constexpr auto confOverridePath = "/etc/phosphor-fan-presence";
38constexpr auto confBasePath = "/usr/share/phosphor-fan-presence";
39constexpr auto confDbusPath = "/xyz/openbmc_project/inventory/system/chassis";
40constexpr auto confDbusIntf =
41 "xyz.openbmc_project.Inventory.Decorator.Compatible";
42constexpr auto confDbusProp = "Names";
43
44class JsonConfig
45{
46 public:
47 /**
48 * Get the json configuration file. The first location found to contain
49 * the json config file for the given fan application is used from the
50 * following locations in order.
51 * 1.) From the confOverridePath location
52 * 2.) From config file found using a property value as a relative
53 * path extension on the base path from the dbus object where:
54 * path = Path set in confDbusPath
55 * interface = Interface set in confDbusIntf
56 * property = Property set in confDbusProp
57 * 3.) *DEFAULT* - From the confBasePath location
58 *
59 * @brief Get the configuration file to be used
60 *
61 * @param[in] bus - The dbus bus object
62 * @param[in] appName - The phosphor-fan-presence application name
63 * @param[in] fileName - Application's configuration file's name
Matthew Barthb5991022020-08-05 11:08:50 -050064 * @param[in] isOptional - Config file is optional, default to 'false'
Matthew Barth11547c92020-05-05 10:34:27 -050065 *
66 * @return filesystem path
67 * The filesystem path to the configuration file to use
68 */
69 static const fs::path getConfFile(sdbusplus::bus::bus& bus,
70 const std::string& appName,
Matthew Barthb5991022020-08-05 11:08:50 -050071 const std::string& fileName,
72 bool isOptional = false)
Matthew Barth11547c92020-05-05 10:34:27 -050073 {
74 // Check override location
75 fs::path confFile = fs::path{confOverridePath} / appName / fileName;
76 if (fs::exists(confFile))
77 {
78 return confFile;
79 }
80
81 try
82 {
83 // Retrieve json config relative path location from dbus
84 auto confDbusValue =
85 util::SDBusPlus::getProperty<std::vector<std::string>>(
86 bus, confDbusPath, confDbusIntf, confDbusProp);
87 // Look for a config file at each entry relative to the base
88 // path and use the first one found
89 auto it = std::find_if(
90 confDbusValue.begin(), confDbusValue.end(),
91 [&confFile, &appName, &fileName](auto const& entry) {
92 confFile =
93 fs::path{confBasePath} / appName / entry / fileName;
94 return fs::exists(confFile);
95 });
96 if (it == confDbusValue.end())
97 {
98 // Property exists, but no config file found. Use default base
99 // path
100 confFile = fs::path{confBasePath} / appName / fileName;
101 }
102 }
103 catch (const util::DBusError&)
104 {
105 // Property unavailable, attempt default base path
106 confFile = fs::path{confBasePath} / appName / fileName;
107 }
108
Matthew Bartha916f032020-08-17 10:51:48 -0500109 if (!fs::exists(confFile))
Matthew Barth11547c92020-05-05 10:34:27 -0500110 {
Matthew Bartha916f032020-08-17 10:51:48 -0500111 if (!isOptional)
112 {
Matthew Barth1826c732020-08-28 08:40:59 -0500113 log<level::ERR>(
114 fmt::format("No JSON config file found. Default file: {}",
115 confFile.string())
116 .c_str());
117 throw std::runtime_error(
118 fmt::format("No JSON config file found. Default file: {}",
119 confFile.string())
120 .c_str());
Matthew Bartha916f032020-08-17 10:51:48 -0500121 }
122 else
123 {
124 confFile.clear();
125 }
Matthew Barthb5991022020-08-05 11:08:50 -0500126 }
Matthew Barth11547c92020-05-05 10:34:27 -0500127
128 return confFile;
129 }
130
131 /**
132 * @brief Load the JSON config file
133 *
134 * @param[in] confFile - File system path of the configuration file to load
135 *
136 * @return Parsed JSON object
137 * The parsed JSON configuration file object
138 */
139 static const json load(const fs::path& confFile)
140 {
141 std::ifstream file;
142 json jsonConf;
143
Matthew Barthb5991022020-08-05 11:08:50 -0500144 if (!confFile.empty() && fs::exists(confFile))
Matthew Barth11547c92020-05-05 10:34:27 -0500145 {
Matthew Barth1826c732020-08-28 08:40:59 -0500146 log<level::INFO>(
147 fmt::format("Loading configuration from {}", confFile.string())
148 .c_str());
Matthew Barth11547c92020-05-05 10:34:27 -0500149 file.open(confFile);
150 try
151 {
152 jsonConf = json::parse(file);
153 }
154 catch (std::exception& e)
155 {
Matthew Barth1826c732020-08-28 08:40:59 -0500156 log<level::ERR>(
157 fmt::format(
158 "Failed to parse JSON config file: {}, error: {}",
159 confFile.string(), e.what())
160 .c_str());
161 throw std::runtime_error(
162 fmt::format(
163 "Failed to parse JSON config file: {}, error: {}",
164 confFile.string(), e.what())
165 .c_str());
Matthew Barth11547c92020-05-05 10:34:27 -0500166 }
167 }
168 else
169 {
Matthew Barth1826c732020-08-28 08:40:59 -0500170 log<level::ERR>(fmt::format("Unable to open JSON config file: {}",
171 confFile.string())
172 .c_str());
173 throw std::runtime_error(
174 fmt::format("Unable to open JSON config file: {}",
175 confFile.string())
176 .c_str());
Matthew Barth11547c92020-05-05 10:34:27 -0500177 }
178
179 return jsonConf;
180 }
181};
182
183} // namespace phosphor::fan