blob: 6ea73d19d3575dd6333fae2de4bdece6b0d4eef0 [file] [log] [blame]
#include "config.h"
#include "host_state_manager.hpp"
#include "settings.hpp"
#include "utils.hpp"
#include "xyz/openbmc_project/Common/error.hpp"
#include "xyz/openbmc_project/Control/Power/RestorePolicy/server.hpp"
#include <getopt.h>
#include <systemd/sd-bus.h>
#include <phosphor-logging/elog-errors.hpp>
#include <phosphor-logging/lg2.hpp>
#include <sdbusplus/exception.hpp>
#include <sdbusplus/server.hpp>
#include <iostream>
#include <map>
#include <string>
namespace phosphor
{
namespace state
{
namespace manager
{
PHOSPHOR_LOG2_USING;
using namespace phosphor::logging;
using namespace sdbusplus::xyz::openbmc_project::Common::Error;
using namespace sdbusplus::xyz::openbmc_project::Control::Power::server;
} // namespace manager
} // namespace state
} // namespace phosphor
int main(int argc, char** argv)
{
using namespace phosphor::logging;
std::string hostPath = "/xyz/openbmc_project/state/host0";
int arg;
int optIndex = 0;
static struct option longOpts[] = {{"host", required_argument, 0, 'h'},
{0, 0, 0, 0}};
while ((arg = getopt_long(argc, argv, "h:", longOpts, &optIndex)) != -1)
{
switch (arg)
{
case 'h':
hostPath =
std::string("/xyz/openbmc_project/state/host") + optarg;
break;
default:
break;
}
}
auto bus = sdbusplus::bus::new_default();
using namespace settings;
Objects settings(bus);
using namespace phosphor::state::manager;
namespace server = sdbusplus::xyz::openbmc_project::State::server;
// This application is only run if chassis power is off
// If the BMC was rebooted due to a user initiated pinhole reset, do not
// implement any power restore policies
auto bmcRebootCause = phosphor::state::manager::utils::getProperty(
bus, "/xyz/openbmc_project/state/bmc0", BMC_BUSNAME, "LastRebootCause");
if (bmcRebootCause ==
"xyz.openbmc_project.State.BMC.RebootCause.PinholeReset")
{
info(
"BMC was reset due to pinhole reset, no power restore policy will be run");
return 0;
}
else if (bmcRebootCause ==
"xyz.openbmc_project.State.BMC.RebootCause.Watchdog")
{
info(
"BMC was reset due to cold reset, no power restore policy will be run");
return 0;
}
/* The logic here is to first check the one-time PowerRestorePolicy setting.
* If this property is not the default then look at the persistent
* user setting in the non one-time object, otherwise honor the one-time
* setting.
*/
auto methodOneTime = bus.new_method_call(
settings.service(settings.powerRestorePolicy, powerRestoreIntf).c_str(),
settings.powerRestorePolicyOneTime.c_str(),
"org.freedesktop.DBus.Properties", "Get");
methodOneTime.append(powerRestoreIntf, "PowerRestorePolicy");
auto methodUserSetting = bus.new_method_call(
settings.service(settings.powerRestorePolicy, powerRestoreIntf).c_str(),
settings.powerRestorePolicy.c_str(), "org.freedesktop.DBus.Properties",
"Get");
methodUserSetting.append(powerRestoreIntf, "PowerRestorePolicy");
std::variant<std::string> result;
try
{
auto reply = bus.call(methodOneTime);
reply.read(result);
auto powerPolicy = std::get<std::string>(result);
if (RestorePolicy::Policy::None ==
RestorePolicy::convertPolicyFromString(powerPolicy))
{
// one_time is set to None so use the customer setting
info("One time not set, check user setting of power policy");
auto reply = bus.call(methodUserSetting);
reply.read(result);
powerPolicy = std::get<std::string>(result);
}
else
{
// one_time setting was set so we're going to use it. Reset it
// to default for next time.
info("One time set, use it and reset to default");
phosphor::state::manager::utils::setProperty(
bus, settings.powerRestorePolicyOneTime.c_str(),
powerRestoreIntf, "PowerRestorePolicy",
convertForMessage(RestorePolicy::Policy::None));
}
info("Host power is off, processing power policy {POWER_POLICY}",
"POWER_POLICY", powerPolicy);
if (RestorePolicy::Policy::AlwaysOn ==
RestorePolicy::convertPolicyFromString(powerPolicy))
{
info("power_policy=ALWAYS_POWER_ON, powering host on");
phosphor::state::manager::utils::setProperty(
bus, hostPath, HOST_BUSNAME, "RestartCause",
convertForMessage(
server::Host::RestartCause::PowerPolicyAlwaysOn));
phosphor::state::manager::utils::setProperty(
bus, hostPath, HOST_BUSNAME, "RequestedHostTransition",
convertForMessage(server::Host::Transition::On));
}
else if (RestorePolicy::Policy::AlwaysOff ==
RestorePolicy::convertPolicyFromString(powerPolicy))
{
info("power_policy=ALWAYS_POWER_OFF, set requested state to off");
// Read last requested state and re-request it to execute it
auto hostReqState = phosphor::state::manager::utils::getProperty(
bus, hostPath, HOST_BUSNAME, "RequestedHostTransition");
if (hostReqState == convertForMessage(server::Host::Transition::On))
{
phosphor::state::manager::utils::setProperty(
bus, hostPath, HOST_BUSNAME, "RequestedHostTransition",
convertForMessage(server::Host::Transition::Off));
}
}
else if (RestorePolicy::Policy::Restore ==
RestorePolicy::convertPolicyFromString(powerPolicy))
{
info("power_policy=RESTORE, restoring last state");
// Read last requested state and re-request it to execute it
auto hostReqState = phosphor::state::manager::utils::getProperty(
bus, hostPath, HOST_BUSNAME, "RequestedHostTransition");
if (hostReqState == convertForMessage(server::Host::Transition::On))
{
phosphor::state::manager::utils::setProperty(
bus, hostPath, HOST_BUSNAME, "RestartCause",
convertForMessage(
server::Host::RestartCause::PowerPolicyPreviousState));
phosphor::state::manager::utils::setProperty(
bus, hostPath, HOST_BUSNAME, "RequestedHostTransition",
hostReqState);
}
}
}
catch (const sdbusplus::exception::exception& e)
{
error("Error in PowerRestorePolicy Get: {ERROR}", "ERROR", e);
elog<InternalFailure>();
}
return 0;
}