blob: 506c8c0d00ce617c5ed9a7483ca7a45304d3bb03 [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"
19#include "group.hpp"
Matthew Barthacd737c2021-03-04 11:04:01 -060020#include "json_config.hpp"
Matthew Barth06764942021-03-04 09:28:40 -060021#include "profile.hpp"
Matthew Barthacd737c2021-03-04 11:04:01 -060022#include "zone.hpp"
Matthew Barth06764942021-03-04 09:28:40 -060023
Matthew Bartha227a162020-08-05 10:51:45 -050024#include <nlohmann/json.hpp>
25#include <sdbusplus/bus.hpp>
Matthew Barth06764942021-03-04 09:28:40 -060026#include <sdeventplus/event.hpp>
Matthew Barthd9cb63b2021-03-24 14:36:49 -050027#include <sdeventplus/utility/timer.hpp>
28
29#include <chrono>
30#include <map>
31#include <memory>
32#include <optional>
33#include <tuple>
34#include <utility>
35#include <vector>
Matthew Bartha227a162020-08-05 10:51:45 -050036
37namespace phosphor::fan::control::json
38{
39
40using json = nlohmann::json;
41
Matthew Barthacd737c2021-03-04 11:04:01 -060042/* Application name to be appended to the path for loading a JSON config file */
43constexpr auto confAppName = "control";
44
45/**
46 * Configuration object key to uniquely map to the configuration object
47 * Pair constructed of:
48 * std::string = Configuration object's name
49 * std::vector<std::string> = List of profiles the configuration object
50 * is included in
51 */
52using configKey = std::pair<std::string, std::vector<std::string>>;
53
Matthew Barthd9cb63b2021-03-24 14:36:49 -050054/* Type of timers supported */
55enum class TimerType
56{
57 oneshot,
58 repeating,
59};
60/**
61 * Package of data required when a timer expires
62 * Tuple constructed of:
63 * std::string = Timer package unique identifier
64 * Zone = Zone object to run the actions against
65 * Group = Group of dbus objects for the actions
66 * std::vector<std::unique_ptr<ActionBase>> = List of pointers to actions
67 * that run when the timer expires
68 */
69using TimerPkg = std::tuple<std::string, Zone&, const Group&,
70 std::vector<std::unique_ptr<ActionBase>>&>;
71/**
72 * Data associated with a running timer that's used when it expires
73 * Pair constructed of:
74 * TimerType = Type of timer to manage expired timer instances
75 * TimerPkg = Package of data required when the timer expires
76 */
77using TimerData = std::pair<TimerType, TimerPkg>;
78/* Dbus event timer */
79using Timer = sdeventplus::utility::Timer<sdeventplus::ClockId::Monotonic>;
80
Matthew Bartha227a162020-08-05 10:51:45 -050081/**
82 * @class Manager - Represents the fan control manager's configuration
83 *
84 * A fan control manager configuration is optional, therefore the "manager.json"
85 * file is also optional. The manager configuration is used to populate
86 * fan control's manager parameters which are used in how the application
87 * operates, not in how the fans are controlled.
88 *
89 * When no manager configuration exists, the fan control application starts,
90 * processes any configured events and then begins controlling fans according
91 * to those events.
92 */
93class Manager
94{
95 public:
96 Manager() = delete;
97 Manager(const Manager&) = delete;
98 Manager(Manager&&) = delete;
99 Manager& operator=(const Manager&) = delete;
100 Manager& operator=(Manager&&) = delete;
101 ~Manager() = default;
102
103 /**
104 * Constructor
105 * Parses and populates the fan control manager attributes from a json file
106 *
107 * @param[in] bus - sdbusplus bus object
Matthew Barth06764942021-03-04 09:28:40 -0600108 * @param[in] event - sdeventplus event loop
Matthew Bartha227a162020-08-05 10:51:45 -0500109 */
Matthew Barth06764942021-03-04 09:28:40 -0600110 Manager(sdbusplus::bus::bus& bus, const sdeventplus::Event& event);
Matthew Bartha227a162020-08-05 10:51:45 -0500111
112 /**
Matthew Barthacd737c2021-03-04 11:04:01 -0600113 * @brief Get the active profiles of the system where an empty list
114 * represents that only configuration entries without a profile defined will
115 * be loaded.
116 *
117 * @return - The list of active profiles
118 */
119 static const std::vector<std::string>& getActiveProfiles();
120
121 /**
122 * @brief Load the configuration of a given JSON class object based on the
123 * active profiles
124 *
Matthew Barthacd737c2021-03-04 11:04:01 -0600125 * @param[in] isOptional - JSON configuration file is optional or not
Matthew Barth603ef162021-03-24 15:34:53 -0500126 * @param[in] bus - The sdbusplus bus object
127 * @param[in] args - Arguments to be forwarded to each instance of `T`
Matthew Barthacd737c2021-03-04 11:04:01 -0600128 *
129 * @return Map of configuration entries
130 * Map of configuration keys to their corresponding configuration object
131 */
Matthew Barth603ef162021-03-24 15:34:53 -0500132 template <typename T, typename... Args>
Matthew Barthacd737c2021-03-04 11:04:01 -0600133 static std::map<configKey, std::unique_ptr<T>>
Matthew Barth603ef162021-03-24 15:34:53 -0500134 getConfig(bool isOptional, sdbusplus::bus::bus& bus, Args&&... args)
Matthew Barthacd737c2021-03-04 11:04:01 -0600135 {
136 std::map<configKey, std::unique_ptr<T>> config;
137
138 auto confFile = fan::JsonConfig::getConfFile(
139 bus, confAppName, T::confFileName, isOptional);
140 if (!confFile.empty())
141 {
142 for (const auto& entry : fan::JsonConfig::load(confFile))
143 {
144 if (entry.contains("profiles"))
145 {
146 std::vector<std::string> profiles;
147 for (const auto& profile : entry["profiles"])
148 {
149 profiles.emplace_back(
150 profile.template get<std::string>());
151 }
152 // Do not create the object if its profiles are not in the
153 // list of active profiles
154 if (!std::any_of(profiles.begin(), profiles.end(),
155 [](const auto& name) {
156 return std::find(
157 getActiveProfiles().begin(),
158 getActiveProfiles().end(),
159 name) !=
160 getActiveProfiles().end();
161 }))
162 {
163 continue;
164 }
165 }
Matthew Barth603ef162021-03-24 15:34:53 -0500166 auto obj =
167 std::make_unique<T>(entry, std::forward<Args>(args)...);
Matthew Barthacd737c2021-03-04 11:04:01 -0600168 config.emplace(
169 std::make_pair(obj->getName(), obj->getProfiles()),
170 std::move(obj));
171 }
172 }
173 return config;
174 }
175
176 /**
Matthew Barth12cb1252021-03-08 16:47:30 -0600177 * @brief Check if the given path and inteface is owned by a dbus service
178 *
179 * @param[in] path - Dbus object path
180 * @param[in] intf - Dbus object interface
181 *
182 * @return - Whether the service has an owner for the given object path and
183 * interface
184 */
185 static bool hasOwner(const std::string& path, const std::string& intf);
186
187 /**
Matthew Barth07fecfc2021-01-29 09:04:43 -0600188 * @brief Get the object's property value as a variant
189 *
190 * @param[in] path - Path of the object containing the property
191 * @param[in] intf - Interface name containing the property
192 * @param[in] prop - Name of property
193 *
194 * @return - The object's property value as a variant
195 */
196 static inline auto getObjValueVariant(const std::string& path,
197 const std::string& intf,
198 const std::string& prop)
199 {
200 return _objects.at(path).at(intf).at(prop);
201 };
202
203 /**
Matthew Barthd9cb63b2021-03-24 14:36:49 -0500204 * @brief Add a dbus timer
205 *
206 * @param[in] type - Type of timer
207 * @param[in] interval - Timer interval in microseconds
208 * @param[in] pkg - Packaged data for when timer expires
209 */
210 void addTimer(const TimerType type,
211 const std::chrono::microseconds interval,
212 std::unique_ptr<TimerPkg> pkg);
213
214 /**
215 * @brief Callback when a timer expires
216 *
217 * @param[in] data - Data to be used when the timer expired
218 */
219 void timerExpired(TimerData& data);
220
221 /**
Matthew Bartha227a162020-08-05 10:51:45 -0500222 * @brief Get the configured power on delay(OPTIONAL)
223 *
224 * @return Power on delay in seconds
225 * Configured power on delay in seconds, otherwise 0
226 */
227 unsigned int getPowerOnDelay();
228
229 private:
230 /* JSON file name for manager configuration attributes */
231 static constexpr auto confFileName = "manager.json";
232
233 /* The parsed JSON object */
234 json _jsonObj;
Matthew Barth06764942021-03-04 09:28:40 -0600235
Matthew Barthacd737c2021-03-04 11:04:01 -0600236 /**
237 * The sdbusplus bus object to use
238 */
239 sdbusplus::bus::bus& _bus;
240
241 /**
242 * The sdeventplus even loop to use
243 */
244 sdeventplus::Event _event;
245
Matthew Barth06764942021-03-04 09:28:40 -0600246 /* List of profiles configured */
Matthew Barthacd737c2021-03-04 11:04:01 -0600247 std::map<configKey, std::unique_ptr<Profile>> _profiles;
Matthew Barth06764942021-03-04 09:28:40 -0600248
249 /* List of active profiles */
Matthew Barthacd737c2021-03-04 11:04:01 -0600250 static std::vector<std::string> _activeProfiles;
251
Matthew Barth12cb1252021-03-08 16:47:30 -0600252 /* Subtree map of paths to services (with ownership state) of interfaces */
253 static std::map<std::string, std::map<std::pair<std::string, bool>,
254 std::vector<std::string>>>
255 _servTree;
256
Matthew Barth07fecfc2021-01-29 09:04:43 -0600257 /* Object map of paths to interfaces of properties and their values */
258 static std::map<
259 std::string,
260 std::map<std::string, std::map<std::string, PropertyVariantType>>>
261 _objects;
262
Matthew Barthd9cb63b2021-03-24 14:36:49 -0500263 /* List of timers and their data to be processed when expired */
264 std::vector<std::pair<std::unique_ptr<TimerData>, Timer>> _timers;
265
Matthew Barthacd737c2021-03-04 11:04:01 -0600266 /* List of zones configured */
267 std::map<configKey, std::unique_ptr<Zone>> _zones;
268
269 /**
270 * @brief Parse and set the configured profiles from the profiles JSON file
271 *
272 * Retrieves the optional profiles JSON configuration file, parses it, and
273 * creates a list of configured profiles available to the other
274 * configuration files. These profiles can be used to remove or include
275 * entries within the other configuration files.
276 */
277 void setProfiles();
Matthew Bartha227a162020-08-05 10:51:45 -0500278};
279
280} // namespace phosphor::fan::control::json