monitor: Create PowerOffCause class hierarchy
The PowerOffCause base class and its derived classes will be used to
determine when a power off needs to be done based on fan failures.
The 'satisified()' method, which takes the fan health map, is used to
say if the cause is satisfied and a shut down will need to occur.
It provides two types of causes:
* MissingFanFRUCause - Looks at missing fan FRUs
* NonfuncFanRotorCause - Looks at nonfunctional rotors (sensors)
Signed-off-by: Matt Spinler <spinler@us.ibm.com>
Change-Id: I3c43347782dc559eb7c7441bf9c03d3407b248e2
diff --git a/monitor/power_off_cause.hpp b/monitor/power_off_cause.hpp
new file mode 100644
index 0000000..f40e1fe
--- /dev/null
+++ b/monitor/power_off_cause.hpp
@@ -0,0 +1,169 @@
+#pragma once
+
+#include "types.hpp"
+
+#include <algorithm>
+#include <vector>
+
+namespace phosphor::fan::monitor
+{
+
+/**
+ * @class PowerOffCause
+ *
+ * This abstract class provides a satisfied() pure virtual method
+ * that is called to know if the system should be powered off due
+ * to fan health. Each type of class that is derived from this
+ * one provides different behavior, for example one may count
+ * missing fans, and another may count nonfunctional fans.
+ */
+class PowerOffCause
+{
+ public:
+ PowerOffCause() = delete;
+ virtual ~PowerOffCause() = default;
+ PowerOffCause(const PowerOffCause&) = delete;
+ PowerOffCause& operator=(const PowerOffCause&) = delete;
+ PowerOffCause(PowerOffCause&&) = delete;
+ PowerOffCause& operator=(PowerOffCause&&) = delete;
+
+ /**
+ * @brief Constructor
+ *
+ * @param[in] count - The number of items that is compared
+ * against in the derived class.
+ * @param[in] name - The name of the cause. Used for tracing.
+ */
+ PowerOffCause(size_t count, const std::string& name) :
+ _count(count), _name(std::to_string(count) + " " + name)
+ {}
+
+ /**
+ * @brief Pure virtual that says if the system should be powered
+ * off based on the fan health.
+ *
+ * @param[in] fanHealth - The FanHealth map
+ *
+ * @return bool - If system should be powered off
+ */
+ virtual bool satisfied(const FanHealth& fanHealth) = 0;
+
+ /**
+ * @brief Returns the name of the cause.
+ *
+ * For example: "3 Missing Fans"
+ *
+ * @return std::string - The name
+ */
+ const std::string& name() const
+ {
+ return _name;
+ }
+
+ protected:
+ /**
+ * @brief The number of fan health items that the derived
+ * class uses to compare to the fan health status.
+ * For example, a 3 for 3 missing fans.
+ */
+ const size_t _count;
+
+ /**
+ * @brief The cause name
+ */
+ const std::string _name;
+};
+
+/**
+ * @class MissingFanFRUCause
+ *
+ * This class provides a satisfied() method that checks for
+ * missing fans in the fan health map.
+ *
+ */
+class MissingFanFRUCause : public PowerOffCause
+{
+ public:
+ MissingFanFRUCause() = delete;
+ ~MissingFanFRUCause() = default;
+ MissingFanFRUCause(const MissingFanFRUCause&) = delete;
+ MissingFanFRUCause& operator=(const MissingFanFRUCause&) = delete;
+ MissingFanFRUCause(MissingFanFRUCause&&) = delete;
+ MissingFanFRUCause& operator=(MissingFanFRUCause&&) = delete;
+
+ /**
+ * @brief Constructor
+ *
+ * @param[in] count - The minimum number of fans that must be
+ * missing to need a power off.
+ */
+ explicit MissingFanFRUCause(size_t count) :
+ PowerOffCause(count, "Missing Fan FRUs")
+ {}
+
+ /**
+ * @brief Returns true if 'count' or more fans are missing
+ * to require a power off.
+ *
+ * @param[in] fanHealth - The FanHealth map
+ */
+ bool satisfied(const FanHealth& fanHealth) override
+ {
+ size_t count = std::count_if(
+ fanHealth.begin(), fanHealth.end(), [](const auto& fan) {
+ return !std::get<presentHealthPos>(fan.second);
+ });
+
+ return count >= _count;
+ }
+};
+
+/**
+ * @class NonfuncFanRotorCause
+ *
+ * This class provides a satisfied() method that checks for
+ * nonfunctional fan rotors in the fan health map.
+ */
+class NonfuncFanRotorCause : public PowerOffCause
+{
+ public:
+ NonfuncFanRotorCause() = delete;
+ ~NonfuncFanRotorCause() = default;
+ NonfuncFanRotorCause(const NonfuncFanRotorCause&) = delete;
+ NonfuncFanRotorCause& operator=(const NonfuncFanRotorCause&) = delete;
+ NonfuncFanRotorCause(NonfuncFanRotorCause&&) = delete;
+ NonfuncFanRotorCause& operator=(NonfuncFanRotorCause&&) = delete;
+
+ /**
+ * @brief Constructor
+ *
+ * @param[in] count - The minimum number of rotors that must be
+ * nonfunctional nonfunctional to need a power off.
+ */
+ explicit NonfuncFanRotorCause(size_t count) :
+ PowerOffCause(count, "Nonfunctional Fan Rotors")
+ {}
+
+ /**
+ * @brief Returns true if 'count' or more rotors are nonfunctional
+ * to require a power off.
+ *
+ * @param[in] fanHealth - The FanHealth map
+ */
+ bool satisfied(const FanHealth& fanHealth) override
+ {
+ size_t count = std::accumulate(
+ fanHealth.begin(), fanHealth.end(), 0,
+ [](int sum, const auto& fan) {
+ const auto& tachs = std::get<sensorFuncHealthPos>(fan.second);
+ auto nonFuncTachs =
+ std::count_if(tachs.begin(), tachs.end(),
+ [](bool tach) { return !tach; });
+ return sum + nonFuncTachs;
+ });
+
+ return count >= _count;
+ }
+};
+
+} // namespace phosphor::fan::monitor