summaryrefslogtreecommitdiff
path: root/srvcfg-manager
diff options
context:
space:
mode:
authorRichard Marian Thomaiyar <richard.marian.thomaiyar@linux.intel.com>2019-05-23 03:07:50 +0300
committerRichard Marian Thomaiyar <richard.marian.thomaiyar@linux.intel.com>2019-06-07 06:32:32 +0300
commit14e9d25e60ff48a54fd66633b7a72365d5bfd749 (patch)
treee38e38ddf771256e0e0c831eb93348634e6d44e7 /srvcfg-manager
parent94b8e4dbd4bd5f916ba47d9c810e14a8fdf48ca8 (diff)
downloadprovingground-14e9d25e60ff48a54fd66633b7a72365d5bfd749.tar.xz
srvcfg: Updated for dynamic service/socket mgmt
Fixed srvcfg crash manager issue, by doing the service & socket unit file queries dynamically and exposing the objects to be controlled. This takes care of instanced service & socket files like phosphor-ipmi-net@eth0 or phosphor-ipmi-net@eth1 dynamically. Tested: 1. Verified as per the base service name, all the instanced service & socket names are dynamically queried and exposed 2. Made sure to list the disabled services thorugh this method 3. Made sure new services listed after fw-update are also exposed as objects 4. Verfied phosphor-ipmi-net@eth0 port change using ipmitool -p <newport> option 5. Verified permanent disable of the unit. 6. Verified run time enable / disable of the service. 7. Verified phosphor-ipmi-kcs service permanent & run time enable / disable Change-Id: Ib933a2fbff73eae4348a5940d350ae7972db03fb Signed-off-by: Richard Marian Thomaiyar <richard.marian.thomaiyar@linux.intel.com>
Diffstat (limited to 'srvcfg-manager')
-rw-r--r--srvcfg-manager/CMakeLists.txt6
-rw-r--r--srvcfg-manager/inc/srvcfg_manager.hpp61
-rw-r--r--srvcfg-manager/inc/utils.hpp35
-rw-r--r--srvcfg-manager/src/main.cpp280
-rw-r--r--srvcfg-manager/src/srvcfg_manager.cpp574
-rw-r--r--srvcfg-manager/src/utils.cpp187
-rw-r--r--srvcfg-manager/srvcfg-manager.service2
7 files changed, 763 insertions, 382 deletions
diff --git a/srvcfg-manager/CMakeLists.txt b/srvcfg-manager/CMakeLists.txt
index 6dd3e29..8511943 100644
--- a/srvcfg-manager/CMakeLists.txt
+++ b/srvcfg-manager/CMakeLists.txt
@@ -2,8 +2,6 @@ cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
project(phosphor-srvcfg-manager CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
-set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")
-set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fno-rtti")
set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE)
@@ -17,6 +15,7 @@ add_definitions(-DBOOST_ALL_NO_LIB)
add_definitions(-DBOOST_NO_RTTI)
add_definitions(-DBOOST_NO_TYPEID)
add_definitions(-DBOOST_ASIO_DISABLE_THREADS)
+add_definitions(-DBOOST_COROUTINES_NO_DEPRECATION_WARNING)
set(SRC_FILES src/main.cpp src/srvcfg_manager.cpp src/utils.cpp)
@@ -50,9 +49,10 @@ target_link_libraries(${PROJECT_NAME} systemd)
target_link_libraries(${PROJECT_NAME} "${SDBUSPLUSPLUS_LIBRARIES} -lstdc++fs")
target_link_libraries(${PROJECT_NAME} ${DBUSINTERFACE_LIBRARIES})
target_link_libraries(${PROJECT_NAME} ${Boost_LIBRARIES})
+target_link_libraries(${PROJECT_NAME} boost_coroutine)
target_link_libraries(${PROJECT_NAME} phosphor_logging)
set(SERVICE_FILES ${PROJECT_SOURCE_DIR}/srvcfg-manager.service)
-install(TARGETS ${PROJECT_NAME} DESTINATION sbin)
+install(TARGETS ${PROJECT_NAME} DESTINATION bin)
install(FILES ${SERVICE_FILES} DESTINATION /lib/systemd/system/)
diff --git a/srvcfg-manager/inc/srvcfg_manager.hpp b/srvcfg-manager/inc/srvcfg_manager.hpp
index 8979f78..8974b29 100644
--- a/srvcfg-manager/inc/srvcfg_manager.hpp
+++ b/srvcfg-manager/inc/srvcfg_manager.hpp
@@ -26,43 +26,80 @@ static constexpr const char *serviceConfigSrvName =
"xyz.openbmc_project.Control.Service.Manager";
static constexpr const char *serviceConfigIntfName =
"xyz.openbmc_project.Control.Service.Attributes";
+static constexpr const char *srcCfgMgrBasePath =
+ "/xyz/openbmc_project/control/service";
+static constexpr const char *srvCfgPropPort = "Port";
+static constexpr const char *srvCfgPropMasked = "Masked";
+static constexpr const char *srvCfgPropEnabled = "Enabled";
+static constexpr const char *srvCfgPropRunning = "Running";
enum class UpdatedProp
{
port = 1,
- channel,
- state
+ maskedState,
+ enabledState,
+ runningState
};
+using VariantType =
+ std::variant<std::string, int64_t, uint64_t, double, int32_t, uint32_t,
+ int16_t, uint16_t, uint8_t, bool,
+ std::vector<std::tuple<std::string, std::string>>>;
+
class ServiceConfig
{
public:
ServiceConfig(sdbusplus::asio::object_server &srv_,
std::shared_ptr<sdbusplus::asio::connection> &conn_,
- std::string objPath_, std::string unitName);
+ const std::string &objPath_, const std::string &baseUnitName,
+ const std::string &instanceName,
+ const std::string &serviceObjPath,
+ const std::string &socketObjPath);
~ServiceConfig() = default;
- void applySystemDServiceConfig();
- void startServiceRestartTimer();
-
std::shared_ptr<sdbusplus::asio::connection> conn;
uint8_t updatedFlag;
+ void stopAndApplyUnitConfig(boost::asio::yield_context yield);
+ void restartUnitConfig(boost::asio::yield_context yield);
+ void startServiceRestartTimer();
+
private:
sdbusplus::asio::object_server &server;
+ std::shared_ptr<sdbusplus::asio::dbus_interface> iface;
+ bool internalSet = false;
std::string objPath;
+ std::string instanceName;
+ std::string baseUnitName;
+ std::string instantiatedUnitName;
+ std::string socketObjectPath;
+ std::string serviceObjectPath;
+ std::string overrideConfDir;
+ // Properties
+ std::string activeState;
+ std::string subState;
uint16_t portNum;
+ std::vector<std::string> channelList;
std::string protocol;
std::string stateValue;
- std::vector<std::string> channelList;
+ bool unitMaskedState = false;
+ bool unitEnabledState = false;
+ bool unitRunningState = false;
+ std::string subStateValue;
+ bool isMaskedOut();
void registerProperties();
- std::string sysDUnitName;
- std::string unitSocketFilePath;
- std::string sysDSockObjPath;
-
- void syncWithSystemD1Properties();
+ void queryAndUpdateProperties();
+ void createSocketOverrideConf();
+ void updateServiceProperties(
+ const boost::container::flat_map<std::string, VariantType>
+ &propertyMap);
+ void updateSocketProperties(
+ const boost::container::flat_map<std::string, VariantType>
+ &propertyMap);
+ std::string getSocketUnitName();
+ std::string getServiceUnitName();
};
} // namespace service
diff --git a/srvcfg-manager/inc/utils.hpp b/srvcfg-manager/inc/utils.hpp
index 27e66f3..5f01d44 100644
--- a/srvcfg-manager/inc/utils.hpp
+++ b/srvcfg-manager/inc/utils.hpp
@@ -23,18 +23,41 @@
#include <experimental/filesystem>
#include <boost/asio.hpp>
-static constexpr const char *sysdActionStartUnit = "StartUnit";
-static constexpr const char *sysdActionStopUnit = "StopUnit";
+static constexpr const char *sysdStartUnit = "StartUnit";
+static constexpr const char *sysdStopUnit = "StopUnit";
+static constexpr const char *sysdRestartUnit = "RestartUnit";
+static constexpr const char *sysdReloadMethod = "Reload";
+static constexpr const char *sysdGetJobMethod = "GetJob";
+static constexpr const char *sysdReplaceMode = "replace";
+static constexpr const char *dBusGetAllMethod = "GetAll";
+static constexpr const char *dBusGetMethod = "Get";
+static constexpr const char *sysdService = "org.freedesktop.systemd1";
+static constexpr const char *sysdObjPath = "/org/freedesktop/systemd1";
+static constexpr const char *sysdMgrIntf = "org.freedesktop.systemd1.Manager";
+static constexpr const char *sysdUnitIntf = "org.freedesktop.systemd1.Unit";
+static constexpr const char *sysdSocketIntf = "org.freedesktop.systemd1.Socket";
+static constexpr const char *dBusPropIntf = "org.freedesktop.DBus.Properties";
+static constexpr const char *stateMasked = "masked";
+static constexpr const char *stateEnabled = "enabled";
+static constexpr const char *stateDisabled = "disabled";
+static constexpr const char *subStateRunning = "running";
+
+static inline std::string addInstanceName(const std::string &instanceName,
+ const std::string &suffix)
+{
+ return (instanceName.empty() ? "" : suffix + instanceName);
+}
void systemdDaemonReload(
- const std::shared_ptr<sdbusplus::asio::connection> &conn);
+ const std::shared_ptr<sdbusplus::asio::connection> &conn,
+ boost::asio::yield_context yield);
void systemdUnitAction(const std::shared_ptr<sdbusplus::asio::connection> &conn,
+ boost::asio::yield_context yield,
const std::string &unitName,
const std::string &actionMethod);
void systemdUnitFilesStateChange(
const std::shared_ptr<sdbusplus::asio::connection> &conn,
- const std::vector<std::string> &unitFiles, const std::string &unitState);
-
-bool checkSystemdUnitExist(const std::string &unitName);
+ boost::asio::yield_context yield, const std::vector<std::string> &unitFiles,
+ const std::string &unitState, bool maskedState, bool enabledState);
diff --git a/srvcfg-manager/src/main.cpp b/srvcfg-manager/src/main.cpp
index abbb0b3..cca4899 100644
--- a/srvcfg-manager/src/main.cpp
+++ b/srvcfg-manager/src/main.cpp
@@ -14,35 +14,287 @@
// limitations under the License.
*/
#include "srvcfg_manager.hpp"
+#include <boost/algorithm/string/replace.hpp>
+#include <sdbusplus/bus/match.hpp>
+#include <filesystem>
+#include <cereal/archives/json.hpp>
+#include <cereal/types/tuple.hpp>
+#include <cereal/types/unordered_map.hpp>
+#include <fstream>
std::shared_ptr<boost::asio::deadline_timer> timer = nullptr;
std::map<std::string, std::shared_ptr<phosphor::service::ServiceConfig>>
srvMgrObjects;
-static std::map<std::string, std::string> serviceList = {
- {"netipmid", "phosphor-ipmi-net"}, {"web", "bmcweb"}, {"ssh", "dropbear"}};
+static constexpr const char* srvCfgMgrFile = "/etc/srvcfg-mgr.json";
+
+// Base service name list. All instance of these services and
+// units(service/socket) will be managed by this daemon.
+static std::vector<std::string> serviceNames = {
+ "phosphor-ipmi-net", "bmcweb", "phosphor-ipmi-kcs", "start-ipkvm"};
+
+using ListUnitsType =
+ std::tuple<std::string, std::string, std::string, std::string, std::string,
+ std::string, sdbusplus::message::object_path, uint32_t,
+ std::string, sdbusplus::message::object_path>;
+
+enum class ListUnitElements
+{
+ name,
+ descriptionString,
+ loadState,
+ activeState,
+ subState,
+ followedUnit,
+ objectPath,
+ queuedJobType,
+ jobType,
+ jobObject
+};
+
+enum class UnitType
+{
+ service,
+ socket,
+ target,
+ device,
+ invalid
+};
+
+using MonitorListMap =
+ std::unordered_map<std::string, std::tuple<std::string, std::string,
+ std::string, std::string>>;
+MonitorListMap unitsToMonitor;
+
+enum class monitorElement
+{
+ unitName,
+ instanceName,
+ serviceObjPath,
+ socketObjPath
+};
+
+std::tuple<std::string, UnitType, std::string>
+ getUnitNameTypeAndInstance(const std::string& fullUnitName)
+{
+ UnitType type = UnitType::invalid;
+ std::string instanceName;
+ std::string unitName;
+ // get service type
+ auto typePos = fullUnitName.rfind(".");
+ if (typePos != std::string::npos)
+ {
+ const auto& typeStr = fullUnitName.substr(typePos + 1);
+ // Ignore types other than service and socket
+ if (typeStr == "service")
+ {
+ type = UnitType::service;
+ }
+ else if (typeStr == "socket")
+ {
+ type = UnitType::socket;
+ }
+ // get instance name if available
+ auto instancePos = fullUnitName.rfind("@");
+ if (instancePos != std::string::npos)
+ {
+ instanceName =
+ fullUnitName.substr(instancePos + 1, typePos - instancePos - 1);
+ unitName = fullUnitName.substr(0, instancePos);
+ }
+ else
+ {
+ unitName = fullUnitName.substr(0, typePos);
+ }
+ }
+ return std::make_tuple(unitName, type, instanceName);
+}
+
+static inline void
+ handleListUnitsResponse(sdbusplus::asio::object_server& server,
+ std::shared_ptr<sdbusplus::asio::connection>& conn,
+ boost::system::error_code ec,
+ const std::vector<ListUnitsType>& listUnits)
+{
+ // Loop through all units, and mark all units, which has to be
+ // managed, irrespective of instance name.
+ for (const auto& unit : listUnits)
+ {
+ const auto& fullUnitName =
+ std::get<static_cast<int>(ListUnitElements::name)>(unit);
+ auto [unitName, type, instanceName] =
+ getUnitNameTypeAndInstance(fullUnitName);
+ if (std::find(serviceNames.begin(), serviceNames.end(), unitName) !=
+ serviceNames.end())
+ {
+ std::string instantiatedUnitName =
+ unitName + addInstanceName(instanceName, "_40");
+ boost::replace_all(instantiatedUnitName, "-", "_2d");
+ const sdbusplus::message::object_path& objectPath =
+ std::get<static_cast<int>(ListUnitElements::objectPath)>(unit);
+ // Group the service & socket units togther.. Same services
+ // are managed together.
+ auto it = unitsToMonitor.find(instantiatedUnitName);
+ if (it != unitsToMonitor.end())
+ {
+ auto& value = it->second;
+ if (type == UnitType::service)
+ {
+ std::get<static_cast<int>(monitorElement::unitName)>(
+ value) = unitName;
+ std::get<static_cast<int>(monitorElement::instanceName)>(
+ value) = instanceName;
+ std::get<static_cast<int>(monitorElement::serviceObjPath)>(
+ value) = objectPath;
+ }
+ else if (type == UnitType::socket)
+ {
+ std::get<static_cast<int>(monitorElement::socketObjPath)>(
+ value) = objectPath;
+ }
+ }
+ if (type == UnitType::service)
+ {
+ unitsToMonitor.emplace(instantiatedUnitName,
+ std::make_tuple(unitName, instanceName,
+ objectPath.str, ""));
+ }
+ else if (type == UnitType::socket)
+ {
+ unitsToMonitor.emplace(
+ instantiatedUnitName,
+ std::make_tuple("", "", "", objectPath.str));
+ }
+ }
+ }
+
+ bool updateRequired = false;
+ bool jsonExist = std::filesystem::exists(srvCfgMgrFile);
+ if (jsonExist)
+ {
+ std::ifstream file(srvCfgMgrFile);
+ cereal::JSONInputArchive archive(file);
+ MonitorListMap savedMonitorList;
+ archive(savedMonitorList);
+
+ // compare the unit list read from systemd1 and the save list.
+ MonitorListMap diffMap;
+ std::set_difference(begin(unitsToMonitor), end(unitsToMonitor),
+ begin(savedMonitorList), end(savedMonitorList),
+ std::inserter(diffMap, begin(diffMap)));
+ for (auto& unitIt : diffMap)
+ {
+ auto it = savedMonitorList.find(unitIt.first);
+ if (it == savedMonitorList.end())
+ {
+ savedMonitorList.insert(unitIt);
+ updateRequired = true;
+ }
+ }
+ unitsToMonitor = savedMonitorList;
+ }
+ if (!jsonExist || updateRequired)
+ {
+ std::ofstream file(srvCfgMgrFile);
+ cereal::JSONOutputArchive archive(file);
+ archive(CEREAL_NVP(unitsToMonitor));
+ }
+
+ // create objects for needed services
+ for (auto& it : unitsToMonitor)
+ {
+ std::string objPath(std::string(phosphor::service::srcCfgMgrBasePath) +
+ "/" + it.first);
+ std::string instanciatedUnitName =
+ std::get<static_cast<int>(monitorElement::unitName)>(it.second) +
+ addInstanceName(
+ std::get<static_cast<int>(monitorElement::instanceName)>(
+ it.second),
+ "@");
+ auto srvCfgObj = std::make_unique<phosphor::service::ServiceConfig>(
+ server, conn, objPath,
+ std::get<static_cast<int>(monitorElement::unitName)>(it.second),
+ std::get<static_cast<int>(monitorElement::instanceName)>(it.second),
+ std::get<static_cast<int>(monitorElement::serviceObjPath)>(
+ it.second),
+ std::get<static_cast<int>(monitorElement::socketObjPath)>(
+ it.second));
+ srvMgrObjects.emplace(
+ std::make_pair(std::move(objPath), std::move(srvCfgObj)));
+ }
+}
+
+void init(sdbusplus::asio::object_server& server,
+ std::shared_ptr<sdbusplus::asio::connection>& conn)
+{
+ // Go through all systemd units, and dynamically detect and manage
+ // the service daemons
+ conn->async_method_call(
+ [&server, &conn](boost::system::error_code ec,
+ const std::vector<ListUnitsType>& listUnits) {
+ if (ec)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "async_method_call error: ListUnits failed");
+ return;
+ }
+ handleListUnitsResponse(server, conn, ec, listUnits);
+ },
+ sysdService, sysdObjPath, sysdMgrIntf, "ListUnits");
+}
+
+void checkAndInit(sdbusplus::asio::object_server& server,
+ std::shared_ptr<sdbusplus::asio::connection>& conn)
+{
+ // Check whether systemd completed all the loading before initializing
+ conn->async_method_call(
+ [&server, &conn](boost::system::error_code ec,
+ const std::variant<uint64_t>& value) {
+ if (ec)
+ {
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "async_method_call error: ListUnits failed");
+ return;
+ }
+ if (std::get<uint64_t>(value))
+ {
+ if (!srvMgrObjects.size())
+ {
+ init(server, conn);
+ }
+ }
+ },
+ sysdService, sysdObjPath, dBusPropIntf, dBusGetMethod, sysdMgrIntf,
+ "FinishTimestamp");
+}
int main()
{
- // setup connection to dbus
boost::asio::io_service io;
auto conn = std::make_shared<sdbusplus::asio::connection>(io);
timer = std::make_shared<boost::asio::deadline_timer>(io);
conn->request_name(phosphor::service::serviceConfigSrvName);
auto server = sdbusplus::asio::object_server(conn, true);
auto mgrInterface =
- server.add_interface("/xyz/openbmc_project/control/service", "");
+ server.add_interface(phosphor::service::srcCfgMgrBasePath, "");
mgrInterface->initialize();
- server.add_manager("/xyz/openbmc_project/control/service");
- for (const auto &service : serviceList)
- {
- std::string objPath("/xyz/openbmc_project/control/service/" +
- service.first);
- auto srvCfgObj = std::make_unique<phosphor::service::ServiceConfig>(
- server, conn, objPath, service.second);
- srvMgrObjects.emplace(
- std::make_pair(std::move(service.first), std::move(srvCfgObj)));
- }
+ server.add_manager(phosphor::service::srcCfgMgrBasePath);
+ // Initialize the objects after systemd indicated startup finished.
+ auto userUpdatedSignal = std::make_unique<sdbusplus::bus::match::match>(
+ static_cast<sdbusplus::bus::bus&>(*conn),
+ "type='signal',"
+ "member='StartupFinished',path='/org/freedesktop/systemd1',"
+ "interface='org.freedesktop.systemd1.Manager'",
+ [&server, &conn](sdbusplus::message::message& msg) {
+ if (!srvMgrObjects.size())
+ {
+ init(server, conn);
+ }
+ });
+ // this will make sure to initialize the objects, when daemon is
+ // restarted.
+ checkAndInit(server, conn);
+
io.run();
return 0;
diff --git a/srvcfg-manager/src/srvcfg_manager.cpp b/srvcfg-manager/src/srvcfg_manager.cpp
index 333c001..69217d7 100644
--- a/srvcfg-manager/src/srvcfg_manager.cpp
+++ b/srvcfg-manager/src/srvcfg_manager.cpp
@@ -15,11 +15,13 @@
*/
#include <fstream>
#include <regex>
+#include <boost/asio/spawn.hpp>
#include "srvcfg_manager.hpp"
extern std::shared_ptr<boost::asio::deadline_timer> timer;
extern std::map<std::string, std::shared_ptr<phosphor::service::ServiceConfig>>
srvMgrObjects;
+static bool updateInProgress = false;
namespace phosphor
{
@@ -34,207 +36,231 @@ static constexpr const char *systemd1UnitBasePath =
static constexpr const char *systemdOverrideUnitBasePath =
"/etc/systemd/system/";
-void ServiceConfig::syncWithSystemD1Properties()
+void ServiceConfig::updateSocketProperties(
+ const boost::container::flat_map<std::string, VariantType> &propertyMap)
+{
+ auto listenIt = propertyMap.find("Listen");
+ if (listenIt != propertyMap.end())
+ {
+ auto listenVal =
+ std::get<std::vector<std::tuple<std::string, std::string>>>(
+ listenIt->second);
+ if (listenVal.size())
+ {
+ protocol = std::get<0>(listenVal[0]);
+ std::string port = std::get<1>(listenVal[0]);
+ auto tmp = std::stoul(port.substr(port.find_last_of(":") + 1),
+ nullptr, 10);
+ if (tmp > std::numeric_limits<uint16_t>::max())
+ {
+ throw std::out_of_range("Out of range");
+ }
+ portNum = tmp;
+ if (iface && iface->is_initialized())
+ {
+ internalSet = true;
+ iface->set_property(srvCfgPropPort, portNum);
+ internalSet = false;
+ }
+ }
+ }
+}
+
+void ServiceConfig::updateServiceProperties(
+ const boost::container::flat_map<std::string, VariantType> &propertyMap)
+{
+ auto stateIt = propertyMap.find("UnitFileState");
+ if (stateIt != propertyMap.end())
+ {
+ stateValue = std::get<std::string>(stateIt->second);
+ unitEnabledState = unitMaskedState = false;
+ if (stateValue == stateMasked)
+ {
+ unitMaskedState = true;
+ }
+ else if (stateValue == stateEnabled)
+ {
+ unitEnabledState = true;
+ }
+ if (iface && iface->is_initialized())
+ {
+ internalSet = true;
+ iface->set_property(srvCfgPropMasked, unitMaskedState);
+ iface->set_property(srvCfgPropEnabled, unitEnabledState);
+ internalSet = false;
+ }
+ }
+ auto subStateIt = propertyMap.find("SubState");
+ if (subStateIt != propertyMap.end())
+ {
+ subStateValue = std::get<std::string>(subStateIt->second);
+ if (subStateValue == subStateRunning)
+ {
+ unitRunningState = true;
+ }
+ if (iface && iface->is_initialized())
+ {
+ internalSet = true;
+ iface->set_property(srvCfgPropRunning, unitRunningState);
+ internalSet = false;
+ }
+ }
+}
+
+void ServiceConfig::queryAndUpdateProperties()
{
- // Read systemd1 socket/service property and load.
conn->async_method_call(
[this](boost::system::error_code ec,
- const sdbusplus::message::variant<
- std::vector<std::tuple<std::string, std::string>>> &value) {
+ const boost::container::flat_map<std::string, VariantType>
+ &propertyMap) {
if (ec)
{
phosphor::logging::log<phosphor::logging::level::ERR>(
- "async_method_call error: Failed to get property");
+ "async_method_call error: Failed to service unit "
+ "properties");
return;
}
-
try
{
- auto listenVal = sdbusplus::message::variant_ns::get<
- std::vector<std::tuple<std::string, std::string>>>(value);
- protocol = std::get<0>(listenVal[0]);
- std::string port = std::get<1>(listenVal[0]);
- auto tmp = std::stoul(port.substr(port.find_last_of(":") + 1),
- nullptr, 10);
- if (tmp > std::numeric_limits<uint16_t>::max())
+ updateServiceProperties(propertyMap);
+ if (!socketObjectPath.empty())
{
- throw std::out_of_range("Out of range");
+ conn->async_method_call(
+ [this](boost::system::error_code ec,
+ const boost::container::flat_map<
+ std::string, VariantType> &propertyMap) {
+ if (ec)
+ {
+ phosphor::logging::log<
+ phosphor::logging::level::ERR>(
+ "async_method_call error: Failed to get "
+ "all property");
+ return;
+ }
+ try
+ {
+ updateSocketProperties(propertyMap);
+ if (!iface)
+ {
+ registerProperties();
+ }
+ }
+ catch (const std::exception &e)
+ {
+ phosphor::logging::log<
+ phosphor::logging::level::ERR>(
+ "Exception in getting socket properties",
+ phosphor::logging::entry("WHAT=%s",
+ e.what()));
+ return;
+ }
+ },
+ sysdService, socketObjectPath, dBusPropIntf,
+ dBusGetAllMethod, sysdSocketIntf);
+ }
+ else if (!iface)
+ {
+ registerProperties();
}
- portNum = tmp;
}
catch (const std::exception &e)
{
phosphor::logging::log<phosphor::logging::level::ERR>(
- "Exception for port number",
+ "Exception in getting socket properties",
phosphor::logging::entry("WHAT=%s", e.what()));
return;
}
- conn->async_method_call(
- [](boost::system::error_code ec) {
- if (ec)
- {
- phosphor::logging::log<phosphor::logging::level::ERR>(
- "async_method_call error: Failed to set property");
- return;
- }
- },
- serviceConfigSrvName, objPath.c_str(),
- "org.freedesktop.DBus.Properties", "Set", serviceConfigIntfName,
- "Port", sdbusplus::message::variant<uint16_t>(portNum));
},
- "org.freedesktop.systemd1", sysDSockObjPath.c_str(),
- "org.freedesktop.DBus.Properties", "Get",
- "org.freedesktop.systemd1.Socket", "Listen");
-
- conn->async_method_call(
- [this](boost::system::error_code ec,
- const sdbusplus::message::variant<std::string> &pValue) {
- if (ec)
- {
- phosphor::logging::log<phosphor::logging::level::ERR>(
- "async_method_call error: Failed to get property");
- return;
- }
-
- channelList.clear();
- std::istringstream stm(
- sdbusplus::message::variant_ns::get<std::string>(pValue));
- std::string token;
- while (std::getline(stm, token, ','))
- {
- channelList.push_back(token);
- }
- conn->async_method_call(
- [](boost::system::error_code ec) {
- if (ec)
- {
- phosphor::logging::log<phosphor::logging::level::ERR>(
- "async_method_call error: Failed to set property");
- return;
- }
- },
- serviceConfigSrvName, objPath.c_str(),
- "org.freedesktop.DBus.Properties", "Set", serviceConfigIntfName,
- "Channel",
- sdbusplus::message::variant<std::vector<std::string>>(
- channelList));
- },
- "org.freedesktop.systemd1", sysDSockObjPath.c_str(),
- "org.freedesktop.DBus.Properties", "Get",
- "org.freedesktop.systemd1.Socket", "BindToDevice");
+ sysdService, serviceObjectPath, dBusPropIntf, dBusGetAllMethod,
+ sysdUnitIntf);
+ return;
+}
- std::string srvUnitName(sysDUnitName);
- if (srvUnitName == "dropbear")
+void ServiceConfig::createSocketOverrideConf()
+{
+ if (!socketObjectPath.empty())
{
- // Dropbear service expects template arguments.
- srvUnitName.append("@");
- }
- srvUnitName.append(".service");
- conn->async_method_call(
- [this](boost::system::error_code ec, const std::string &pValue) {
- if (ec)
+ std::string socketUnitName(instantiatedUnitName + ".socket");
+ /// Check override socket directory exist, if not create it.
+ std::experimental::filesystem::path ovrUnitFileDir(
+ systemdOverrideUnitBasePath);
+ ovrUnitFileDir += socketUnitName;
+ ovrUnitFileDir += ".d";
+ if (!std::experimental::filesystem::exists(ovrUnitFileDir))
+ {
+ if (!std::experimental::filesystem::create_directories(
+ ovrUnitFileDir))
{
phosphor::logging::log<phosphor::logging::level::ERR>(
- "async_method_call error: Failed to get property");
- return;
- }
- if ((pValue == "enabled") || (pValue == "static") ||
- (pValue == "unmasked"))
- {
- stateValue = "enabled";
- }
- else if ((pValue == "disabled") || (pValue == "masked"))
- {
- stateValue = "disabled";
+ "Unable to create the directory.",
+ phosphor::logging::entry("DIR=%s", ovrUnitFileDir.c_str()));
+ phosphor::logging::elog<sdbusplus::xyz::openbmc_project::
+ Common::Error::InternalFailure>();
}
- conn->async_method_call(
- [](boost::system::error_code ec) {
- if (ec)
- {
- phosphor::logging::log<phosphor::logging::level::ERR>(
- "async_method_call error: Failed to set property");
- return;
- }
- },
- serviceConfigSrvName, objPath.c_str(),
- "org.freedesktop.DBus.Properties", "Set", serviceConfigIntfName,
- "State", sdbusplus::message::variant<std::string>(stateValue));
- },
- "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager", "GetUnitFileState", srvUnitName);
-
- return;
+ }
+ overrideConfDir = std::string(ovrUnitFileDir);
+ }
}
ServiceConfig::ServiceConfig(
sdbusplus::asio::object_server &srv_,
- std::shared_ptr<sdbusplus::asio::connection> &conn_, std::string objPath_,
- std::string unitName) :
+ std::shared_ptr<sdbusplus::asio::connection> &conn_,
+ const std::string &objPath_, const std::string &baseUnitName_,
+ const std::string &instanceName_, const std::string &serviceObjPath_,
+ const std::string &socketObjPath_) :
server(srv_),
- conn(conn_), objPath(objPath_), sysDUnitName(unitName)
+ conn(conn_), objPath(objPath_), baseUnitName(baseUnitName_),
+ instanceName(instanceName_), serviceObjectPath(serviceObjPath_),
+ socketObjectPath(socketObjPath_)
{
- std::string socketUnitName(sysDUnitName + ".socket");
- // .socket systemd service files are handled.
- // Regular .service only files are ignored.
- if (!checkSystemdUnitExist(socketUnitName))
- {
- phosphor::logging::log<phosphor::logging::level::ERR>(
- "Unit doesn't exist.",
- phosphor::logging::entry("UNITNAME=%s", socketUnitName.c_str()));
- phosphor::logging::elog<
- sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure>();
- }
-
- /// Check override socket directory exist, if not create it.
- std::experimental::filesystem::path ovrUnitFileDir(
- systemdOverrideUnitBasePath);
- ovrUnitFileDir += socketUnitName;
- ovrUnitFileDir += ".d";
- if (!std::experimental::filesystem::exists(ovrUnitFileDir))
- {
- if (!std::experimental::filesystem::create_directories(ovrUnitFileDir))
- {
- phosphor::logging::log<phosphor::logging::level::ERR>(
- "Unable to create the directory.",
- phosphor::logging::entry("DIR=%s", ovrUnitFileDir.c_str()));
- phosphor::logging::elog<sdbusplus::xyz::openbmc_project::Common::
- Error::InternalFailure>();
- }
- }
-
- /* Store require info locally */
- unitSocketFilePath = std::string(ovrUnitFileDir);
-
- sysDSockObjPath = systemd1UnitBasePath;
- sysDSockObjPath.append(
- std::regex_replace(sysDUnitName, std::regex("-"), "_2d"));
- sysDSockObjPath.append("_2esocket");
+ instantiatedUnitName = baseUnitName + addInstanceName(instanceName, "@");
+ updatedFlag = 0;
+ queryAndUpdateProperties();
+ return;
+}
- // Adds interface, object and Properties....
- registerProperties();
+std::string ServiceConfig::getSocketUnitName()
+{
+ return instantiatedUnitName + ".socket";
+}
- syncWithSystemD1Properties();
+std::string ServiceConfig::getServiceUnitName()
+{
+ return instantiatedUnitName + ".service";
+}
- updatedFlag = 0;
- return;
+bool ServiceConfig::isMaskedOut()
+{
+ // return true if state is masked & no request to update the maskedState
+ return (
+ stateValue == "masked" &&
+ !(updatedFlag & (1 << static_cast<uint8_t>(UpdatedProp::maskedState))));
}
-void ServiceConfig::applySystemDServiceConfig()
+void ServiceConfig::stopAndApplyUnitConfig(boost::asio::yield_context yield)
{
- if (updatedFlag)
+ if (!updatedFlag || isMaskedOut())
{
- // No updates. Just return.
+ // No updates / masked - Just return.
return;
}
-
phosphor::logging::log<phosphor::logging::level::INFO>(
"Applying new settings.",
phosphor::logging::entry("OBJPATH=%s", objPath.c_str()));
- if (updatedFlag & ((1 << static_cast<uint8_t>(UpdatedProp::channel)) |
- (1 << static_cast<uint8_t>(UpdatedProp::port))))
+ if (subStateValue == "running")
{
+ if (!socketObjectPath.empty())
+ {
+ systemdUnitAction(conn, yield, getSocketUnitName(), sysdStopUnit);
+ }
+ systemdUnitAction(conn, yield, getServiceUnitName(), sysdStopUnit);
+ }
+
+ if (updatedFlag & (1 << static_cast<uint8_t>(UpdatedProp::port)))
+ {
+ createSocketOverrideConf();
// Create override config file and write data.
- std::string ovrCfgFile{unitSocketFilePath + "/" + overrideConfFileName};
+ std::string ovrCfgFile{overrideConfDir + "/" + overrideConfFileName};
std::string tmpFile{ovrCfgFile + "_tmp"};
std::ofstream cfgFile(tmpFile, std::ios::out);
if (!cfgFile.good())
@@ -251,21 +277,6 @@ void ServiceConfig::applySystemDServiceConfig()
cfgFile << "Listen" << protocol << "="
<< "\n";
cfgFile << "Listen" << protocol << "=" << portNum << "\n";
- // BindToDevice
- bool firstElement = true;
- cfgFile << "BindToDevice=";
- for (const auto &it : channelList)
- {
- if (firstElement)
- {
- cfgFile << it;
- firstElement = false;
- }
- else
- {
- cfgFile << "," << it;
- }
- }
cfgFile.close();
if (std::rename(tmpFile.c_str(), ovrCfgFile.c_str()) != 0)
@@ -278,55 +289,49 @@ void ServiceConfig::applySystemDServiceConfig()
}
}
- std::string socketUnitName(sysDUnitName + ".socket");
- std::string srvUnitName(sysDUnitName);
- if (srvUnitName == "dropbear")
+ if (updatedFlag & ((1 << static_cast<uint8_t>(UpdatedProp::maskedState)) |
+ (1 << static_cast<uint8_t>(UpdatedProp::enabledState))))
{
- // Dropbear service expects template arguments.
- // Todo: Unit action for service, fails with error
- // "missing the instance name". Needs to implement
- // getting all running instances and use it. This
- // impact runtime but works fine during reboot.
- srvUnitName.append("@");
- }
- srvUnitName.append(".service");
- // Stop the running service in below scenarios.
- // 1. State changed from "enabled" to "disabled"
- // 2. No change in state and existing stateValue is
- // "enabled" and there is change in other properties.
- if (((stateValue == "disabled") &&
- (updatedFlag & (1 << static_cast<uint8_t>(UpdatedProp::state)))) ||
- (!(updatedFlag & (1 << static_cast<uint8_t>(UpdatedProp::state))) &&
- (stateValue == "enabled") && (updatedFlag)))
- {
- systemdUnitAction(conn, socketUnitName, "StopUnit");
- systemdUnitAction(conn, srvUnitName, "StopUnit");
+ std::vector<std::string> unitFiles;
+ if (socketObjectPath.empty())
+ {
+ unitFiles = {getServiceUnitName()};
+ }
+ else
+ {
+ unitFiles = {getSocketUnitName(), getServiceUnitName()};
+ }
+ systemdUnitFilesStateChange(conn, yield, unitFiles, stateValue,
+ unitMaskedState, unitEnabledState);
}
-
- if (updatedFlag & (1 << static_cast<uint8_t>(UpdatedProp::state)))
+ return;
+}
+void ServiceConfig::restartUnitConfig(boost::asio::yield_context yield)
+{
+ if (!updatedFlag || isMaskedOut())
{
- std::vector<std::string> unitFiles = {socketUnitName, srvUnitName};
- systemdUnitFilesStateChange(conn, unitFiles, stateValue);
+ // No updates. Just return.
+ return;
}
- // Perform daemon reload to read new settings
- systemdDaemonReload(conn);
-
- if (stateValue == "enabled")
+ if (unitRunningState)
{
- // Restart the socket
- systemdUnitAction(conn, socketUnitName, "StartUnit");
+ if (!socketObjectPath.empty())
+ {
+ systemdUnitAction(conn, yield, getSocketUnitName(),
+ sysdRestartUnit);
+ }
+ systemdUnitAction(conn, yield, getServiceUnitName(), sysdRestartUnit);
}
// Reset the flag
updatedFlag = 0;
- // All done. Lets reload the properties which are applied on systemd1.
- // TODO: We need to capture the service restart signal and reload data
- // inside the signal handler. So that we can update the service
- // properties modified, outside of this service as well.
- syncWithSystemD1Properties();
+ phosphor::logging::log<phosphor::logging::level::INFO>(
+ "Applied new settings",
+ phosphor::logging::entry("OBJPATH=%s", objPath.c_str()));
+ queryAndUpdateProperties();
return;
}
@@ -345,67 +350,144 @@ void ServiceConfig::startServiceRestartTimer()
"async wait error.");
return;
}
- for (auto &srvMgrObj : srvMgrObjects)
- {
- auto &srvObj = srvMgrObj.second;
- if (srvObj->updatedFlag)
- {
- srvObj->applySystemDServiceConfig();
- }
- }
+ updateInProgress = true;
+ boost::asio::spawn(conn->get_io_context(),
+ [this](boost::asio::yield_context yield) {
+ // Stop and apply configuration for all objects
+ for (auto &srvMgrObj : srvMgrObjects)
+ {
+ auto &srvObj = srvMgrObj.second;
+ if (srvObj->updatedFlag)
+ {
+ srvObj->stopAndApplyUnitConfig(yield);
+ }
+ }
+ // Do system reload
+ systemdDaemonReload(conn, yield);
+ // restart unit config.
+ for (auto &srvMgrObj : srvMgrObjects)
+ {
+ auto &srvObj = srvMgrObj.second;
+ if (srvObj->updatedFlag)
+ {
+ srvObj->restartUnitConfig(yield);
+ }
+ }
+ updateInProgress = false;
+ });
});
}
void ServiceConfig::registerProperties()
{
- std::shared_ptr<sdbusplus::asio::dbus_interface> iface =
- server.add_interface(objPath, serviceConfigIntfName);
+ iface = server.add_interface(objPath, serviceConfigIntfName);
+
+ if (!socketObjectPath.empty())
+ {
+ iface->register_property(
+ srvCfgPropPort, portNum,
+ [this](const uint16_t &req, uint16_t &res) {
+ if (!internalSet)
+ {
+ if (req == res)
+ {
+ return 1;
+ }
+ if (updateInProgress)
+ {
+ return 0;
+ }
+ portNum = req;
+ updatedFlag |=
+ (1 << static_cast<uint8_t>(UpdatedProp::port));
+ startServiceRestartTimer();
+ }
+ res = req;
+ return 1;
+ });
+ }
iface->register_property(
- "Port", portNum, [this](const uint16_t &req, uint16_t &res) {
- if (req == res)
+ srvCfgPropMasked, unitMaskedState, [this](const bool &req, bool &res) {
+ if (!internalSet)
{
- return 1;
+ if (req == res)
+ {
+ return 1;
+ }
+ if (updateInProgress)
+ {
+ return 0;
+ }
+ unitMaskedState = req;
+ unitEnabledState = !unitMaskedState;
+ unitRunningState = !unitMaskedState;
+ updatedFlag |=
+ (1 << static_cast<uint8_t>(UpdatedProp::maskedState)) |
+ (1 << static_cast<uint8_t>(UpdatedProp::enabledState)) |
+ (1 << static_cast<uint8_t>(UpdatedProp::runningState));
+ internalSet = true;
+ iface->set_property(srvCfgPropEnabled, unitEnabledState);
+ iface->set_property(srvCfgPropRunning, unitRunningState);
+ internalSet = false;
+ startServiceRestartTimer();
}
- portNum = req;
- updatedFlag |= (1 << static_cast<uint8_t>(UpdatedProp::port));
- startServiceRestartTimer();
res = req;
return 1;
});
iface->register_property(
- "Channel", channelList,
- [this](const std::vector<std::string> &req,
- std::vector<std::string> &res) {
- if (req == res)
+ srvCfgPropEnabled, unitEnabledState,
+ [this](const bool &req, bool &res) {
+ if (!internalSet)
{
- return 1;
+ if (req == res)
+ {
+ return 1;
+ }
+ if (updateInProgress)
+ {
+ return 0;
+ }
+ if (unitMaskedState)
+ { // block updating if masked
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "Invalid value specified");
+ return -EINVAL;
+ }
+ unitEnabledState = req;
+ updatedFlag |=
+ (1 << static_cast<uint8_t>(UpdatedProp::enabledState));
+ startServiceRestartTimer();
}
- channelList.clear();
- std::copy(req.begin(), req.end(), back_inserter(channelList));
-
- updatedFlag |= (1 << static_cast<uint8_t>(UpdatedProp::channel));
- startServiceRestartTimer();
res = req;
return 1;
});
iface->register_property(
- "State", stateValue, [this](const std::string &req, std::string &res) {
- if (req == res)
+ srvCfgPropRunning, unitRunningState,
+ [this](const bool &req, bool &res) {
+ if (!internalSet)
{
- return 1;
- }
- if ((req != "enabled") && (req != "disabled"))
- {
- phosphor::logging::log<phosphor::logging::level::ERR>(
- "Invalid value specified");
- return -EINVAL;
+ if (req == res)
+ {
+ return 1;
+ }
+ if (updateInProgress)
+ {
+ return 0;
+ }
+ if (unitMaskedState)
+ { // block updating if masked
+ phosphor::logging::log<phosphor::logging::level::ERR>(
+ "Invalid value specified");
+ return -EINVAL;
+ }
+ unitRunningState = req;
+ updatedFlag |=
+ (1 << static_cast<uint8_t>(UpdatedProp::runningState));
+ startServiceRestartTimer();
}
- stateValue = req;
- updatedFlag |= (1 << static_cast<uint8_t>(UpdatedProp::state));
- startServiceRestartTimer();
res = req;
return 1;
});
diff --git a/srvcfg-manager/src/utils.cpp b/srvcfg-manager/src/utils.cpp
index 32ac69d..cf15dee 100644
--- a/srvcfg-manager/src/utils.cpp
+++ b/srvcfg-manager/src/utils.cpp
@@ -15,133 +15,120 @@
*/
#include "utils.hpp"
-void systemdDaemonReload(
- const std::shared_ptr<sdbusplus::asio::connection> &conn)
+static inline void checkAndThrowInternalFailure(boost::system::error_code &ec,
+ const std::string &msg)
{
- try
- {
- conn->async_method_call(
- [](boost::system::error_code ec) {
- if (ec)
- {
- phosphor::logging::log<phosphor::logging::level::ERR>(
- "async error: Failed to do systemd reload.");
- return;
- }
- return;
- },
- "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager", "Reload");
- }
- catch (const sdbusplus::exception::SdBusError &e)
+ if (ec)
{
- phosphor::logging::log<phosphor::logging::level::ERR>(
- "daemon-reload operation failed.");
+ std::string msgToLog = ec.message() + (msg.empty() ? "" : " - " + msg);
+ phosphor::logging::log<phosphor::logging::level::ERR>(msgToLog.c_str());
phosphor::logging::elog<
sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure>();
}
+ return;
+}
+void systemdDaemonReload(
+ const std::shared_ptr<sdbusplus::asio::connection> &conn,
+ boost::asio::yield_context yield)
+{
+ boost::system::error_code ec;
+ conn->yield_method_call<>(yield, ec, sysdService, sysdObjPath, sysdMgrIntf,
+ sysdReloadMethod);
+ checkAndThrowInternalFailure(ec, "daemon-reload operation failed");
return;
}
-void systemdUnitAction(const std::shared_ptr<sdbusplus::asio::connection> &conn,
- const std::string &unitName,
- const std::string &actionMethod)
+static inline uint32_t getJobId(const std::string &path)
{
- try
- {
- conn->async_method_call(
- [](boost::system::error_code ec,
- const sdbusplus::message::object_path &objPath) {
- if (ec)
- {
- phosphor::logging::log<phosphor::logging::level::ERR>(
- "async error: Failed to do systemd action");
- return;
- }
- phosphor::logging::log<phosphor::logging::level::ERR>(
- "Created unit action job.",
- phosphor::logging::entry("JobID=%s", objPath.str.c_str()));
- return;
- },
- "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager", actionMethod, unitName,
- "replace");
- }
- catch (const sdbusplus::exception::SdBusError &e)
+ auto pos = path.rfind("/");
+ if (pos == std::string::npos)
{
phosphor::logging::log<phosphor::logging::level::ERR>(
- "Systemd operation failed.",
- phosphor::logging::entry("ACTION=%s", actionMethod.c_str()));
+ "Unable to get job id from job path");
phosphor::logging::elog<
sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure>();
}
-
- return;
+ return static_cast<uint32_t>(std::stoul(path.substr(pos + 1)));
}
-void systemdUnitFilesStateChange(
- const std::shared_ptr<sdbusplus::asio::connection> &conn,
- const std::vector<std::string> &unitFiles, const std::string &unitState)
+void systemdUnitAction(const std::shared_ptr<sdbusplus::asio::connection> &conn,
+ boost::asio::yield_context yield,
+ const std::string &unitName,
+ const std::string &actionMethod)
{
- try
+ boost::system::error_code ec;
+ auto jobPath = conn->yield_method_call<sdbusplus::message::object_path>(
+ yield, ec, sysdService, sysdObjPath, sysdMgrIntf, actionMethod,
+ unitName, sysdReplaceMode);
+ checkAndThrowInternalFailure(ec,
+ "Systemd operation failed, " + actionMethod);
+ // Query the job till it doesn't exist anymore.
+ // this way we guarantee that queued job id is done.
+ // this is needed to make sure dependency list on units are
+ // properly handled.
+ while (1)
{
- if (unitState == "enabled")
+ ec.clear();
+ conn->yield_method_call<>(yield, ec, sysdService, sysdObjPath,
+ sysdMgrIntf, sysdGetJobMethod,
+ getJobId(jobPath.str));
+ if (ec)
{
- conn->async_method_call(
- [](boost::system::error_code ec) {
- if (ec)
- {
- phosphor::logging::log<phosphor::logging::level::ERR>(
- "async error: Failed to perform UnmaskUnitFiles.");
- return;
- }
- return;
- },
- "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager", "UnmaskUnitFiles",
- unitFiles, false);
- }
- else if (unitState == "disabled")
- {
- conn->async_method_call(
- [](boost::system::error_code ec) {
- if (ec)
- {
- phosphor::logging::log<phosphor::logging::level::ERR>(
- "async error: Failed to perform MaskUnitFiles.");
- return;
- }
- return;
- },
- "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager", "MaskUnitFiles", unitFiles,
- false, false);
- }
- else
- {
- // Not supported unit State
+ if (ec.value() == boost::system::errc::no_such_file_or_directory)
+ {
+ // Queued job is done, return now
+ return;
+ }
phosphor::logging::log<phosphor::logging::level::ERR>(
- "invalid Unit state",
- phosphor::logging::entry("STATE=%s", unitState.c_str()));
+ "Systemd operation failed for job query");
phosphor::logging::elog<sdbusplus::xyz::openbmc_project::Common::
Error::InternalFailure>();
}
+ boost::asio::deadline_timer sleepTimer(conn->get_io_context());
+ sleepTimer.expires_from_now(boost::posix_time::milliseconds(20));
+ ec.clear();
+ sleepTimer.async_wait(yield[ec]);
+ checkAndThrowInternalFailure(ec, "Systemd operation timer error");
}
- catch (const sdbusplus::exception::SdBusError &e)
- {
- phosphor::logging::log<phosphor::logging::level::ERR>(
- "Systemd state change operation failed.");
- phosphor::logging::elog<
- sdbusplus::xyz::openbmc_project::Common::Error::InternalFailure>();
- }
-
return;
}
-bool checkSystemdUnitExist(const std::string &unitName)
+void systemdUnitFilesStateChange(
+ const std::shared_ptr<sdbusplus::asio::connection> &conn,
+ boost::asio::yield_context yield, const std::vector<std::string> &unitFiles,
+ const std::string &unitState, bool maskedState, bool enabledState)
{
- std::experimental::filesystem::path unitFilePath(
- std::string("/lib/systemd/system/") + unitName);
- return std::experimental::filesystem::exists(unitFilePath);
+ boost::system::error_code ec;
+
+ if (unitState == stateMasked && !maskedState)
+ {
+ conn->yield_method_call<>(yield, ec, sysdService, sysdObjPath,
+ sysdMgrIntf, "UnmaskUnitFiles", unitFiles,
+ false);
+ checkAndThrowInternalFailure(ec, "Systemd UnmaskUnitFiles() failed.");
+ }
+ else if (unitState != stateMasked && maskedState)
+ {
+ conn->yield_method_call<>(yield, ec, sysdService, sysdObjPath,
+ sysdMgrIntf, "MaskUnitFiles", unitFiles,
+ false, false);
+ checkAndThrowInternalFailure(ec, "Systemd MaskUnitFiles() failed.");
+ }
+ ec.clear();
+ if (unitState != stateEnabled && enabledState)
+ {
+ conn->yield_method_call<>(yield, ec, sysdService, sysdObjPath,
+ sysdMgrIntf, "EnableUnitFiles", unitFiles,
+ false, false);
+ checkAndThrowInternalFailure(ec, "Systemd EnableUnitFiles() failed.");
+ }
+ else if (unitState != stateDisabled && !enabledState)
+ {
+ conn->yield_method_call<>(yield, ec, sysdService, sysdObjPath,
+ sysdMgrIntf, "DisableUnitFiles", unitFiles,
+ false);
+ checkAndThrowInternalFailure(ec, "Systemd DisableUnitFiles() failed.");
+ }
+ return;
}
diff --git a/srvcfg-manager/srvcfg-manager.service b/srvcfg-manager/srvcfg-manager.service
index 42c8fd6..f75a028 100644
--- a/srvcfg-manager/srvcfg-manager.service
+++ b/srvcfg-manager/srvcfg-manager.service
@@ -11,4 +11,4 @@ Type=dbus
BusName=xyz.openbmc_project.Control.Service.Manager
[Install]
-#WantedBy=basic.target
+WantedBy=multi-user.target