call auto power restart when chassis power recovers

When the power status transitions from bad to good, call the Auto
Power-on Restart (APR) functionality to see if the system should be
automatically powered back on.

In most cases, a power issue to the system will result in the BMC
losing power as well. The APR functionality already runs as a part of
the BMC boot. However there are a few situations where the chassis power
may need to be turned off but the BMC will continue to operate on
standby power. This commit addresses that scenario, where once the
chassis power can be turned back on, the BMC runs the APR logic.

This allows systems to get up and running automatically after brownout
and UPS battery low issues.

Note that a change to phosphor-state-manager-systemd-links.inc is
required here to make the APR service a WantedBy vs. RequiredBy
relationship. Restarting a service that is required by multi-user.target
restarts all the other oneshot service in multi-user.target which is not
wanted here. This change will be included with the bump of this
function.

Tested:
- Verified system called APR when CurrentPowerStatus went from
  UninterruptiblePowerSupply to Good
- Verified system did not power on when APR was not set to AlwaysOn
- Verified system did power on when APR was set to AlwaysOn

Signed-off-by: Andrew Geissler <geissonator@yahoo.com>
Change-Id: If9a5e1a91eb8da6e39e021900ad07848eebbdd02
diff --git a/chassis_state_manager.cpp b/chassis_state_manager.cpp
index 3989bca..743727f 100644
--- a/chassis_state_manager.cpp
+++ b/chassis_state_manager.cpp
@@ -45,6 +45,8 @@
 constexpr auto CHASSIS_STATE_POWERON_TGT_FMT = "obmc-chassis-poweron@{}.target";
 constexpr auto RESET_HOST_SENSORS_SVC_FMT =
     "phosphor-reset-sensor-states@{}.service";
+constexpr auto AUTO_POWER_RESTORE_SVC_FMT =
+    "phosphor-discover-system-state@{}.service";
 constexpr auto ACTIVE_STATE = "active";
 constexpr auto ACTIVATING_STATE = "activating";
 
@@ -203,6 +205,8 @@
 
 void Chassis::determineStatusOfPower()
 {
+    auto initialPowerStatus = server::Chassis::currentPowerStatus();
+
     bool powerGood = determineStatusOfUPSPower();
     if (!powerGood)
     {
@@ -214,6 +218,18 @@
     {
         // All checks passed, set power status to good
         server::Chassis::currentPowerStatus(PowerStatus::Good);
+
+        // If power status transitioned from bad to good and chassis power is
+        // off then call Auto Power Restart to see if the system should auto
+        // power on now that power status is good
+        if ((initialPowerStatus != PowerStatus::Good) &&
+            (server::Chassis::currentPowerState() == PowerState::Off))
+        {
+            info("power status transitioned from {START_PWR_STATE} to Good and "
+                 "chassis power is off, calling APR",
+                 "START_PWR_STATE", initialPowerStatus);
+            restartUnit(fmt::format(AUTO_POWER_RESTORE_SVC_FMT, this->id));
+        }
     }
 }
 
@@ -464,6 +480,19 @@
     return;
 }
 
+void Chassis::restartUnit(const std::string& sysdUnit)
+{
+    auto method = this->bus.new_method_call(SYSTEMD_SERVICE, SYSTEMD_OBJ_PATH,
+                                            SYSTEMD_INTERFACE, "RestartUnit");
+
+    method.append(sysdUnit);
+    method.append("replace");
+
+    this->bus.call_noreply(method);
+
+    return;
+}
+
 bool Chassis::stateActive(const std::string& target)
 {
     std::variant<std::string> currentState;