blob: 88fa4ab53753a3340c7d47f9b843c74bd96f151a [file] [log] [blame]
#include "config.h"
#include "host_state_manager.hpp"
#include "settings.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/log.hpp>
#include <sdbusplus/exception.hpp>
#include <sdbusplus/server.hpp>
#include <iostream>
#include <map>
#include <string>
namespace phosphor
{
namespace state
{
namespace manager
{
using namespace phosphor::logging;
using namespace sdbusplus::xyz::openbmc_project::Common::Error;
using namespace sdbusplus::xyz::openbmc_project::Control::Power::server;
using sdbusplus::exception::SdBusError;
constexpr auto MAPPER_BUSNAME = "xyz.openbmc_project.ObjectMapper";
constexpr auto MAPPER_PATH = "/xyz/openbmc_project/object_mapper";
constexpr auto MAPPER_INTERFACE = "xyz.openbmc_project.ObjectMapper";
constexpr auto PROPERTY_INTERFACE = "org.freedesktop.DBus.Properties";
std::string getService(sdbusplus::bus::bus& bus, std::string path,
std::string interface)
{
auto mapper = bus.new_method_call(MAPPER_BUSNAME, MAPPER_PATH,
MAPPER_INTERFACE, "GetObject");
mapper.append(path, std::vector<std::string>({interface}));
std::map<std::string, std::vector<std::string>> mapperResponse;
try
{
auto mapperResponseMsg = bus.call(mapper);
mapperResponseMsg.read(mapperResponse);
if (mapperResponse.empty())
{
log<level::ERR>("Error reading mapper response",
entry("PATH=%s", path.c_str()),
entry("INTERFACE=%s", interface.c_str()));
throw std::runtime_error("Error reading mapper response");
}
}
catch (const SdBusError& e)
{
log<level::ERR>("Error in mapper call", entry("ERROR=%s", e.what()),
entry("PATH=%s", path.c_str()),
entry("INTERFACE=%s", interface.c_str()));
throw;
}
return mapperResponse.begin()->first;
}
std::string getProperty(sdbusplus::bus::bus& bus, std::string path,
std::string interface, std::string propertyName)
{
std::variant<std::string> property;
std::string service = getService(bus, path, interface);
auto method = bus.new_method_call(service.c_str(), path.c_str(),
PROPERTY_INTERFACE, "Get");
method.append(interface, propertyName);
try
{
auto reply = bus.call(method);
reply.read(property);
}
catch (const SdBusError& e)
{
log<level::ERR>("Error in property Get", entry("ERROR=%s", e.what()),
entry("PROPERTY=%s", propertyName.c_str()));
throw;
}
if (std::get<std::string>(property).empty())
{
log<level::ERR>("Error reading property response",
entry("PROPERTY=%s", propertyName.c_str()));
throw std::runtime_error("Error reading property response");
}
return std::get<std::string>(property);
}
void setProperty(sdbusplus::bus::bus& bus, const std::string& path,
const std::string& interface, const std::string& property,
const std::string& value)
{
std::variant<std::string> variantValue = value;
std::string service = getService(bus, path, interface);
auto method = bus.new_method_call(service.c_str(), path.c_str(),
PROPERTY_INTERFACE, "Set");
method.append(interface, property, variantValue);
bus.call_noreply(method);
return;
}
} // 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
/* 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
log<level::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.
log<level::INFO>("One time set, use it and reset to default");
setProperty(bus, settings.powerRestorePolicyOneTime.c_str(),
powerRestoreIntf, "PowerRestorePolicy",
convertForMessage(RestorePolicy::Policy::None));
}
log<level::INFO>("Host power is off, processing power policy",
entry("POWER_POLICY=%s", powerPolicy.c_str()));
if (RestorePolicy::Policy::AlwaysOn ==
RestorePolicy::convertPolicyFromString(powerPolicy))
{
log<level::INFO>("power_policy=ALWAYS_POWER_ON, powering host on");
setProperty(bus, hostPath, HOST_BUSNAME, "RequestedHostTransition",
convertForMessage(server::Host::Transition::On));
}
else if (RestorePolicy::Policy::Restore ==
RestorePolicy::convertPolicyFromString(powerPolicy))
{
log<level::INFO>("power_policy=RESTORE, restoring last state");
// Read last requested state and re-request it to execute it
auto hostReqState = getProperty(bus, hostPath, HOST_BUSNAME,
"RequestedHostTransition");
setProperty(bus, hostPath, HOST_BUSNAME, "RequestedHostTransition",
hostReqState);
}
}
catch (const SdBusError& e)
{
log<level::ERR>("Error in PowerRestorePolicy Get",
entry("ERROR=%s", e.what()));
elog<InternalFailure>();
}
return 0;
}