blob: d6a44996ced5c7f1c9cc2d2eee6233bea62496d2 [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
57 * Zone = Zone object to run the actions against
58 * Group = Group of dbus objects for the actions
59 * std::vector<std::unique_ptr<ActionBase>> = List of pointers to actions
60 * that run when the timer expires
61 */
62using TimerPkg = std::tuple<std::string, Zone&, const Group&,
63 std::vector<std::unique_ptr<ActionBase>>&>;
64/**
65 * Data associated with a running timer that's used when it expires
66 * Pair constructed of:
67 * TimerType = Type of timer to manage expired timer instances
68 * TimerPkg = Package of data required when the timer expires
69 */
70using TimerData = std::pair<TimerType, TimerPkg>;
71/* Dbus event timer */
72using Timer = sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>;
73
Matthew Bartha227a162020-08-05 10:51:45 -050074/**
75 * @class Manager - Represents the fan control manager's configuration
76 *
77 * A fan control manager configuration is optional, therefore the "manager.json"
78 * file is also optional. The manager configuration is used to populate
79 * fan control's manager parameters which are used in how the application
80 * operates, not in how the fans are controlled.
81 *
82 * When no manager configuration exists, the fan control application starts,
83 * processes any configured events and then begins controlling fans according
84 * to those events.
85 */
86class Manager
87{
88 public:
89 Manager() = delete;
90 Manager(const Manager&) = delete;
91 Manager(Manager&&) = delete;
92 Manager& operator=(const Manager&) = delete;
93 Manager& operator=(Manager&&) = delete;
94 ~Manager() = default;
95
96 /**
97 * Constructor
98 * Parses and populates the fan control manager attributes from a json file
99 *
100 * @param[in] bus - sdbusplus bus object
Matthew Barth06764942021-03-04 09:28:40 -0600101 * @param[in] event - sdeventplus event loop
Matthew Bartha227a162020-08-05 10:51:45 -0500102 */
Matthew Barth06764942021-03-04 09:28:40 -0600103 Manager(sdbusplus::bus::bus& bus, const sdeventplus::Event& event);
Matthew Bartha227a162020-08-05 10:51:45 -0500104
105 /**
Matthew Barthacd737c2021-03-04 11:04:01 -0600106 * @brief Get the active profiles of the system where an empty list
107 * represents that only configuration entries without a profile defined will
108 * be loaded.
109 *
110 * @return - The list of active profiles
111 */
112 static const std::vector<std::string>& getActiveProfiles();
113
114 /**
115 * @brief Load the configuration of a given JSON class object based on the
116 * active profiles
117 *
Matthew Barthacd737c2021-03-04 11:04:01 -0600118 * @param[in] isOptional - JSON configuration file is optional or not
Matthew Barth603ef162021-03-24 15:34:53 -0500119 * @param[in] bus - The sdbusplus bus object
120 * @param[in] args - Arguments to be forwarded to each instance of `T`
Matthew Barthacd737c2021-03-04 11:04:01 -0600121 *
122 * @return Map of configuration entries
123 * Map of configuration keys to their corresponding configuration object
124 */
Matthew Barth603ef162021-03-24 15:34:53 -0500125 template <typename T, typename... Args>
Matthew Barthacd737c2021-03-04 11:04:01 -0600126 static std::map<configKey, std::unique_ptr<T>>
Matthew Barth603ef162021-03-24 15:34:53 -0500127 getConfig(bool isOptional, sdbusplus::bus::bus& bus, Args&&... args)
Matthew Barthacd737c2021-03-04 11:04:01 -0600128 {
129 std::map<configKey, std::unique_ptr<T>> config;
130
131 auto confFile = fan::JsonConfig::getConfFile(
132 bus, confAppName, T::confFileName, isOptional);
133 if (!confFile.empty())
134 {
135 for (const auto& entry : fan::JsonConfig::load(confFile))
136 {
137 if (entry.contains("profiles"))
138 {
139 std::vector<std::string> profiles;
140 for (const auto& profile : entry["profiles"])
141 {
142 profiles.emplace_back(
143 profile.template get<std::string>());
144 }
145 // Do not create the object if its profiles are not in the
146 // list of active profiles
Matthew Barth42428052021-03-30 12:50:59 -0500147 if (!profiles.empty() &&
148 !std::any_of(profiles.begin(), profiles.end(),
Matthew Barthacd737c2021-03-04 11:04:01 -0600149 [](const auto& name) {
150 return std::find(
151 getActiveProfiles().begin(),
152 getActiveProfiles().end(),
153 name) !=
154 getActiveProfiles().end();
155 }))
156 {
157 continue;
158 }
159 }
Matthew Barth603ef162021-03-24 15:34:53 -0500160 auto obj =
161 std::make_unique<T>(entry, std::forward<Args>(args)...);
Matthew Barthacd737c2021-03-04 11:04:01 -0600162 config.emplace(
163 std::make_pair(obj->getName(), obj->getProfiles()),
164 std::move(obj));
165 }
166 }
167 return config;
168 }
169
170 /**
Matthew Barth0206c722021-03-30 15:20:05 -0500171 * @brief Check if the given input configuration key matches with another
172 * configuration key that it's to be included in
173 *
174 * @param[in] input - Config key to be included in another config object
175 * @param[in] comp - Config key of the config object to compare with
176 *
177 * @return Whether the configuration object should be included
178 */
179 static bool inConfig(const configKey& input, const configKey& comp);
180
181 /**
Matthew Barth12cb1252021-03-08 16:47:30 -0600182 * @brief Check if the given path and inteface is owned by a dbus service
183 *
184 * @param[in] path - Dbus object path
185 * @param[in] intf - Dbus object interface
186 *
187 * @return - Whether the service has an owner for the given object path and
188 * interface
189 */
190 static bool hasOwner(const std::string& path, const std::string& intf);
191
192 /**
Matthew Barth07fecfc2021-01-29 09:04:43 -0600193 * @brief Get the object's property value as a variant
194 *
195 * @param[in] path - Path of the object containing the property
196 * @param[in] intf - Interface name containing the property
197 * @param[in] prop - Name of property
198 *
199 * @return - The object's property value as a variant
200 */
201 static inline auto getObjValueVariant(const std::string& path,
202 const std::string& intf,
203 const std::string& prop)
204 {
205 return _objects.at(path).at(intf).at(prop);
206 };
207
208 /**
Matthew Barthd9cb63b2021-03-24 14:36:49 -0500209 * @brief Add a dbus timer
210 *
211 * @param[in] type - Type of timer
212 * @param[in] interval - Timer interval in microseconds
213 * @param[in] pkg - Packaged data for when timer expires
214 */
215 void addTimer(const TimerType type,
216 const std::chrono::microseconds interval,
217 std::unique_ptr<TimerPkg> pkg);
218
219 /**
220 * @brief Callback when a timer expires
221 *
222 * @param[in] data - Data to be used when the timer expired
223 */
224 void timerExpired(TimerData& data);
225
226 /**
Matthew Bartha227a162020-08-05 10:51:45 -0500227 * @brief Get the configured power on delay(OPTIONAL)
228 *
229 * @return Power on delay in seconds
230 * Configured power on delay in seconds, otherwise 0
231 */
232 unsigned int getPowerOnDelay();
233
234 private:
235 /* JSON file name for manager configuration attributes */
236 static constexpr auto confFileName = "manager.json";
237
238 /* The parsed JSON object */
239 json _jsonObj;
Matthew Barth06764942021-03-04 09:28:40 -0600240
Matthew Barthacd737c2021-03-04 11:04:01 -0600241 /**
242 * The sdbusplus bus object to use
243 */
244 sdbusplus::bus::bus& _bus;
245
246 /**
247 * The sdeventplus even loop to use
248 */
249 sdeventplus::Event _event;
250
Matthew Barth06764942021-03-04 09:28:40 -0600251 /* List of profiles configured */
Matthew Barthacd737c2021-03-04 11:04:01 -0600252 std::map<configKey, std::unique_ptr<Profile>> _profiles;
Matthew Barth06764942021-03-04 09:28:40 -0600253
254 /* List of active profiles */
Matthew Barthacd737c2021-03-04 11:04:01 -0600255 static std::vector<std::string> _activeProfiles;
256
Matthew Barth12cb1252021-03-08 16:47:30 -0600257 /* Subtree map of paths to services (with ownership state) of interfaces */
258 static std::map<std::string, std::map<std::pair<std::string, bool>,
259 std::vector<std::string>>>
260 _servTree;
261
Matthew Barth07fecfc2021-01-29 09:04:43 -0600262 /* Object map of paths to interfaces of properties and their values */
263 static std::map<
264 std::string,
265 std::map<std::string, std::map<std::string, PropertyVariantType>>>
266 _objects;
267
Matthew Barthd9cb63b2021-03-24 14:36:49 -0500268 /* List of timers and their data to be processed when expired */
269 std::vector<std::pair<std::unique_ptr<TimerData>, Timer>> _timers;
270
Matthew Barthacd737c2021-03-04 11:04:01 -0600271 /* List of zones configured */
272 std::map<configKey, std::unique_ptr<Zone>> _zones;
273
Matthew Barth44ab7692021-03-26 11:40:10 -0500274 /* List of events configured */
275 std::map<configKey, std::unique_ptr<Event>> _events;
276
Matthew Barthacd737c2021-03-04 11:04:01 -0600277 /**
278 * @brief Parse and set the configured profiles from the profiles JSON file
279 *
280 * Retrieves the optional profiles JSON configuration file, parses it, and
281 * creates a list of configured profiles available to the other
282 * configuration files. These profiles can be used to remove or include
283 * entries within the other configuration files.
284 */
285 void setProfiles();
Matthew Bartha227a162020-08-05 10:51:45 -0500286};
287
288} // namespace phosphor::fan::control::json