blob: 1a05a3b4898309a5196cfe113bba257f01b5f203 [file] [log] [blame]
Matthew Bartha227a162020-08-05 10:51:45 -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
Matthew Barthd9cb63b2021-03-24 14:36:49 -050018#include "action.hpp"
Matthew Barth44ab7692021-03-26 11:40:10 -050019#include "config_base.hpp"
20#include "event.hpp"
Matthew Barthd9cb63b2021-03-24 14:36:49 -050021#include "group.hpp"
Matthew Barthacd737c2021-03-04 11:04:01 -060022#include "json_config.hpp"
Matthew Barth06764942021-03-04 09:28:40 -060023#include "profile.hpp"
Matthew Barthacd737c2021-03-04 11:04:01 -060024#include "zone.hpp"
Matthew Barth06764942021-03-04 09:28:40 -060025
Matthew Bartha227a162020-08-05 10:51:45 -050026#include <nlohmann/json.hpp>
27#include <sdbusplus/bus.hpp>
Matthew Barth06764942021-03-04 09:28:40 -060028#include <sdeventplus/event.hpp>
Matthew Barthd9cb63b2021-03-24 14:36:49 -050029#include <sdeventplus/utility/timer.hpp>
30
31#include <chrono>
32#include <map>
33#include <memory>
34#include <optional>
35#include <tuple>
36#include <utility>
37#include <vector>
Matthew Bartha227a162020-08-05 10:51:45 -050038
39namespace phosphor::fan::control::json
40{
41
42using json = nlohmann::json;
43
Matthew Barthacd737c2021-03-04 11:04:01 -060044/* Application name to be appended to the path for loading a JSON config file */
45constexpr auto confAppName = "control";
46
Matthew Barthd9cb63b2021-03-24 14:36:49 -050047/* Type of timers supported */
48enum class TimerType
49{
50 oneshot,
51 repeating,
52};
53/**
54 * Package of data required when a timer expires
55 * Tuple constructed of:
56 * std::string = Timer package unique identifier
Matthew Barthd9cb63b2021-03-24 14:36:49 -050057 * std::vector<std::unique_ptr<ActionBase>> = List of pointers to actions
58 * that run when the timer expires
59 */
Matthew Barth00f6aa02021-04-09 10:49:47 -050060using TimerPkg =
61 std::tuple<std::string, std::vector<std::unique_ptr<ActionBase>>&>;
Matthew Barthd9cb63b2021-03-24 14:36:49 -050062/**
63 * Data associated with a running timer that's used when it expires
64 * Pair constructed of:
65 * TimerType = Type of timer to manage expired timer instances
66 * TimerPkg = Package of data required when the timer expires
67 */
68using TimerData = std::pair<TimerType, TimerPkg>;
69/* Dbus event timer */
70using Timer = sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>;
71
Matthew Bartha227a162020-08-05 10:51:45 -050072/**
73 * @class Manager - Represents the fan control manager's configuration
74 *
75 * A fan control manager configuration is optional, therefore the "manager.json"
76 * file is also optional. The manager configuration is used to populate
77 * fan control's manager parameters which are used in how the application
78 * operates, not in how the fans are controlled.
79 *
80 * When no manager configuration exists, the fan control application starts,
81 * processes any configured events and then begins controlling fans according
82 * to those events.
83 */
84class Manager
85{
86 public:
87 Manager() = delete;
88 Manager(const Manager&) = delete;
89 Manager(Manager&&) = delete;
90 Manager& operator=(const Manager&) = delete;
91 Manager& operator=(Manager&&) = delete;
92 ~Manager() = default;
93
94 /**
95 * Constructor
96 * Parses and populates the fan control manager attributes from a json file
97 *
98 * @param[in] bus - sdbusplus bus object
Matthew Barth06764942021-03-04 09:28:40 -060099 * @param[in] event - sdeventplus event loop
Matthew Bartha227a162020-08-05 10:51:45 -0500100 */
Matthew Barth06764942021-03-04 09:28:40 -0600101 Manager(sdbusplus::bus::bus& bus, const sdeventplus::Event& event);
Matthew Bartha227a162020-08-05 10:51:45 -0500102
103 /**
Matthew Barthacd737c2021-03-04 11:04:01 -0600104 * @brief Get the active profiles of the system where an empty list
105 * represents that only configuration entries without a profile defined will
106 * be loaded.
107 *
108 * @return - The list of active profiles
109 */
110 static const std::vector<std::string>& getActiveProfiles();
111
112 /**
113 * @brief Load the configuration of a given JSON class object based on the
114 * active profiles
115 *
Matthew Barthacd737c2021-03-04 11:04:01 -0600116 * @param[in] isOptional - JSON configuration file is optional or not
Matthew Barth603ef162021-03-24 15:34:53 -0500117 * @param[in] bus - The sdbusplus bus object
118 * @param[in] args - Arguments to be forwarded to each instance of `T`
Matthew Barthacd737c2021-03-04 11:04:01 -0600119 *
120 * @return Map of configuration entries
121 * Map of configuration keys to their corresponding configuration object
122 */
Matthew Barth603ef162021-03-24 15:34:53 -0500123 template <typename T, typename... Args>
Matthew Barthacd737c2021-03-04 11:04:01 -0600124 static std::map<configKey, std::unique_ptr<T>>
Matthew Barth603ef162021-03-24 15:34:53 -0500125 getConfig(bool isOptional, sdbusplus::bus::bus& bus, Args&&... args)
Matthew Barthacd737c2021-03-04 11:04:01 -0600126 {
127 std::map<configKey, std::unique_ptr<T>> config;
128
129 auto confFile = fan::JsonConfig::getConfFile(
130 bus, confAppName, T::confFileName, isOptional);
131 if (!confFile.empty())
132 {
133 for (const auto& entry : fan::JsonConfig::load(confFile))
134 {
135 if (entry.contains("profiles"))
136 {
137 std::vector<std::string> profiles;
138 for (const auto& profile : entry["profiles"])
139 {
140 profiles.emplace_back(
141 profile.template get<std::string>());
142 }
143 // Do not create the object if its profiles are not in the
144 // list of active profiles
Matthew Barth42428052021-03-30 12:50:59 -0500145 if (!profiles.empty() &&
146 !std::any_of(profiles.begin(), profiles.end(),
Matthew Barthacd737c2021-03-04 11:04:01 -0600147 [](const auto& name) {
148 return std::find(
149 getActiveProfiles().begin(),
150 getActiveProfiles().end(),
151 name) !=
152 getActiveProfiles().end();
153 }))
154 {
155 continue;
156 }
157 }
Matthew Barth603ef162021-03-24 15:34:53 -0500158 auto obj =
159 std::make_unique<T>(entry, std::forward<Args>(args)...);
Matthew Barthacd737c2021-03-04 11:04:01 -0600160 config.emplace(
161 std::make_pair(obj->getName(), obj->getProfiles()),
162 std::move(obj));
163 }
164 }
165 return config;
166 }
167
168 /**
Matthew Barth0206c722021-03-30 15:20:05 -0500169 * @brief Check if the given input configuration key matches with another
170 * configuration key that it's to be included in
171 *
172 * @param[in] input - Config key to be included in another config object
173 * @param[in] comp - Config key of the config object to compare with
174 *
175 * @return Whether the configuration object should be included
176 */
177 static bool inConfig(const configKey& input, const configKey& comp);
178
179 /**
Matthew Barth12cb1252021-03-08 16:47:30 -0600180 * @brief Check if the given path and inteface is owned by a dbus service
181 *
182 * @param[in] path - Dbus object path
183 * @param[in] intf - Dbus object interface
184 *
185 * @return - Whether the service has an owner for the given object path and
186 * interface
187 */
188 static bool hasOwner(const std::string& path, const std::string& intf);
189
190 /**
Matthew Barth4ca87fa2021-04-14 11:31:13 -0500191 * @brief Sets the dbus service owner state of a given object
192 *
193 * @param[in] path - Dbus object path
194 * @param[in] serv - Dbus service name
195 * @param[in] intf - Dbus object interface
196 * @param[in] isOwned - Dbus service owner state
197 */
198 void setOwner(const std::string& path, const std::string& serv,
199 const std::string& intf, bool isOwned);
200
201 /**
202 * @brief Add a set of services for a path and interface by retrieving all
203 * the path subtrees to the given depth from root for the interface
204 *
Matthew Barth4ca87fa2021-04-14 11:31:13 -0500205 * @param[in] intf - Interface to add services for
206 * @param[in] depth - Depth of tree traversal from root path
207 *
208 * @throws - DBusMethodError
209 * Throws a DBusMethodError when the `getSubTree` method call fails
210 */
Matthew Barth98f6fc12021-04-16 10:48:37 -0500211 static void addServices(const std::string& intf, int32_t depth);
Matthew Barth4ca87fa2021-04-14 11:31:13 -0500212
213 /**
214 * @brief Get the service for a given path and interface from cached
215 * dataset and attempt to add all the services for the given path/interface
216 * when it's not found
217 *
218 * @param[in] path - Path to get service for
219 * @param[in] intf - Interface to get service for
220 *
221 * @return - The now cached service name
222 *
223 * @throws - DBusMethodError
224 * Ripples up a DBusMethodError exception from calling addServices
225 */
226 static const std::string& getService(const std::string& path,
227 const std::string& intf);
228
229 /**
Matthew Barth07fecfc2021-01-29 09:04:43 -0600230 * @brief Get the object's property value as a variant
231 *
232 * @param[in] path - Path of the object containing the property
233 * @param[in] intf - Interface name containing the property
234 * @param[in] prop - Name of property
235 *
236 * @return - The object's property value as a variant
237 */
238 static inline auto getObjValueVariant(const std::string& path,
239 const std::string& intf,
240 const std::string& prop)
241 {
242 return _objects.at(path).at(intf).at(prop);
243 };
244
245 /**
Matthew Barthd9cb63b2021-03-24 14:36:49 -0500246 * @brief Add a dbus timer
247 *
248 * @param[in] type - Type of timer
249 * @param[in] interval - Timer interval in microseconds
250 * @param[in] pkg - Packaged data for when timer expires
251 */
252 void addTimer(const TimerType type,
253 const std::chrono::microseconds interval,
254 std::unique_ptr<TimerPkg> pkg);
255
256 /**
257 * @brief Callback when a timer expires
258 *
259 * @param[in] data - Data to be used when the timer expired
260 */
261 void timerExpired(TimerData& data);
262
263 /**
Matthew Bartheebde062021-04-14 12:48:52 -0500264 * @brief Get the sdbusplus bus object
265 */
266 inline auto& getBus()
267 {
268 return _bus;
269 }
270
271 /**
Matthew Bartha227a162020-08-05 10:51:45 -0500272 * @brief Get the configured power on delay(OPTIONAL)
273 *
274 * @return Power on delay in seconds
275 * Configured power on delay in seconds, otherwise 0
276 */
277 unsigned int getPowerOnDelay();
278
279 private:
280 /* JSON file name for manager configuration attributes */
281 static constexpr auto confFileName = "manager.json";
282
283 /* The parsed JSON object */
284 json _jsonObj;
Matthew Barth06764942021-03-04 09:28:40 -0600285
Matthew Barthacd737c2021-03-04 11:04:01 -0600286 /**
287 * The sdbusplus bus object to use
288 */
289 sdbusplus::bus::bus& _bus;
290
291 /**
292 * The sdeventplus even loop to use
293 */
294 sdeventplus::Event _event;
295
Matthew Barth06764942021-03-04 09:28:40 -0600296 /* List of profiles configured */
Matthew Barthacd737c2021-03-04 11:04:01 -0600297 std::map<configKey, std::unique_ptr<Profile>> _profiles;
Matthew Barth06764942021-03-04 09:28:40 -0600298
299 /* List of active profiles */
Matthew Barthacd737c2021-03-04 11:04:01 -0600300 static std::vector<std::string> _activeProfiles;
301
Matthew Barth4ca87fa2021-04-14 11:31:13 -0500302 /* Subtree map of paths to services of interfaces(with ownership state) */
303 static std::map<
304 std::string,
305 std::map<std::string, std::pair<bool, std::vector<std::string>>>>
Matthew Barth12cb1252021-03-08 16:47:30 -0600306 _servTree;
307
Matthew Barth07fecfc2021-01-29 09:04:43 -0600308 /* Object map of paths to interfaces of properties and their values */
309 static std::map<
310 std::string,
311 std::map<std::string, std::map<std::string, PropertyVariantType>>>
312 _objects;
313
Matthew Barthd9cb63b2021-03-24 14:36:49 -0500314 /* List of timers and their data to be processed when expired */
315 std::vector<std::pair<std::unique_ptr<TimerData>, Timer>> _timers;
316
Matthew Barthacd737c2021-03-04 11:04:01 -0600317 /* List of zones configured */
318 std::map<configKey, std::unique_ptr<Zone>> _zones;
319
Matthew Barth44ab7692021-03-26 11:40:10 -0500320 /* List of events configured */
321 std::map<configKey, std::unique_ptr<Event>> _events;
322
Matthew Barthacd737c2021-03-04 11:04:01 -0600323 /**
Matthew Barth4ca87fa2021-04-14 11:31:13 -0500324 * @brief Find the service name for a given path and interface from the
325 * cached dataset
326 *
327 * @param[in] path - Path to get service for
328 * @param[in] intf - Interface to get service for
329 *
330 * @return - The cached service name
331 */
332 static const std::string& findService(const std::string& path,
333 const std::string& intf);
334
335 /**
Matthew Barthacd737c2021-03-04 11:04:01 -0600336 * @brief Parse and set the configured profiles from the profiles JSON file
337 *
338 * Retrieves the optional profiles JSON configuration file, parses it, and
339 * creates a list of configured profiles available to the other
340 * configuration files. These profiles can be used to remove or include
341 * entries within the other configuration files.
342 */
343 void setProfiles();
Matthew Bartha227a162020-08-05 10:51:45 -0500344};
345
346} // namespace phosphor::fan::control::json