monitor: Support a separate upper deviation

Add an optional 'upper_deviation' field to the fan monitor config and if
supplied it will be used for the allowed deviation when the fan value is
over the target.  If not supplied it will work as today and the single
deviation value will be used for both the upper and lower bounds.

Signed-off-by: Matt Spinler <spinler@us.ibm.com>
Change-Id: I085dc1996832e79b94bd1df3a05681d107f466eb
diff --git a/monitor/json_parser.cpp b/monitor/json_parser.cpp
index d81d767..4d06540 100644
--- a/monitor/json_parser.cpp
+++ b/monitor/json_parser.cpp
@@ -221,6 +221,24 @@
             throw std::runtime_error(msg.c_str());
         }
 
+        // Upper deviation defaults to the deviation value and
+        // can also be separately specified.
+        size_t upperDeviation = deviation;
+        if (fan.contains("upper_deviation"))
+        {
+            upperDeviation = fan["upper_deviation"].get<size_t>();
+            if (100 < upperDeviation)
+            {
+                auto msg =
+                    fmt::format("Invalid upper_deviation of {} found, must "
+                                "be between 0 and 100",
+                                upperDeviation);
+
+                log<level::ERR>(msg.c_str());
+                throw std::runtime_error(msg.c_str());
+            }
+        }
+
         // Construct the sensor definitions for this fan
         auto sensorDefs = getSensorDefs(fan["sensors"]);
 
@@ -361,6 +379,7 @@
                           .funcDelay = funcDelay,
                           .timeout = timeout,
                           .deviation = deviation,
+                          .upperDeviation = upperDeviation,
                           .numSensorFailsForNonfunc = nonfuncSensorsCount,
                           .monitorStartDelay = monitorDelay,
                           .countInterval = countInterval,