blob: 487f63e3cced24a27a2dd92e25c2c6a979350674 [file] [log] [blame]
Alexander Hansen0119cd72025-01-14 14:15:39 +01001#include "software_manager.hpp"
2
3#include "sdbusplus/async/timer.hpp"
4
5#include <phosphor-logging/lg2.hpp>
6#include <sdbusplus/asio/object_server.hpp>
7#include <sdbusplus/async.hpp>
8#include <sdbusplus/async/context.hpp>
9#include <sdbusplus/bus.hpp>
10#include <xyz/openbmc_project/Association/Definitions/server.hpp>
11#include <xyz/openbmc_project/ObjectMapper/client.hpp>
12#include <xyz/openbmc_project/State/Host/client.hpp>
13
14SoftwareManager::SoftwareManager(sdbusplus::async::context& ctx,
15 const std::string& busNameSuffix,
16 bool isDryRun) :
17 dryRun(isDryRun), ctx(ctx), busNameSuffix(busNameSuffix), manager(ctx, "/")
18{
19 lg2::debug("initialized SoftwareManager");
20}
21
22std::string SoftwareManager::setupBusName()
23{
24 const std::string serviceNameFull =
25 "xyz.openbmc_project.Software." + this->busNameSuffix;
26
27 lg2::debug("requesting dbus name {BUSNAME}", "BUSNAME", serviceNameFull);
28
29 ctx.get_bus().request_name(serviceNameFull.c_str());
30
31 return serviceNameFull;
32}
33
34// NOLINTBEGIN
35sdbusplus::async::task<bool> SoftwareManager::setHostPowerstate(bool state)
36// NOLINTEND
37{
38 auto proxy = sdbusplus::async::proxy()
39 .service("xyz.openbmc_project.State.Host")
40 .path("/xyz/openbmc_project/state/host0")
41 .interface("xyz.openbmc_project.State.Host");
42
43 lg2::info("[PWR] changing host power state to {STATE}", "STATE",
44 (state) ? "ON" : "OFF");
45
46 std::string voff = "xyz.openbmc_project.State.Host.Transition.Off";
47 std::string von = "xyz.openbmc_project.State.Host.Transition.On";
48 std::string targetState;
49 if (state)
50 {
51 co_await proxy.set_property(ctx, "RequestedHostTransition", von);
52 targetState = "xyz.openbmc_project.State.Host.HostState.Running";
53 }
54 else
55 {
56 co_await proxy.set_property(ctx, "RequestedHostTransition", voff);
57 targetState = "xyz.openbmc_project.State.Host.HostState.Off";
58 }
59
60 lg2::debug("[PWR] requested host transition to {STATE}", "STATE",
61 targetState);
62
63 lg2::debug("[PWR] async sleep to wait for state transition");
64 co_await sdbusplus::async::sleep_for(ctx, std::chrono::seconds(10));
65
66 auto actualOpt = co_await getHostPowerstate();
67
68 if (actualOpt == std::nullopt)
69 {
70 co_return false;
71 }
72
73 const bool actual = actualOpt.value();
74
75 if (actual == state)
76 {
77 lg2::debug("[PWR] successfully achieved state {STATE}", "STATE",
78 targetState);
79 co_return true;
80 }
81 else
82 {
83 lg2::debug("[PWR] failed to achieve state {STATE}", "STATE",
84 targetState);
85 co_return false;
86 }
87}
88
89// NOLINTBEGIN
90sdbusplus::async::task<std::optional<bool>> SoftwareManager::getHostPowerstate()
91// NOLINTEND
92{
93 auto proxy = sdbusplus::async::proxy()
94 .service("xyz.openbmc_project.State.Host")
95 .path("/xyz/openbmc_project/state/host0")
96 .interface("xyz.openbmc_project.State.Host");
97
98 std::string stateOn = "xyz.openbmc_project.State.Host.HostState.Running";
99 std::string stateOff = "xyz.openbmc_project.State.Host.HostState.Off";
100
101 std::string res =
102 co_await proxy.get_property<std::string>(ctx, "CurrentHostState");
103
104 if (res == stateOn)
105 {
106 co_return true;
107 }
108 else if (res == stateOff)
109 {
110 co_return false;
111 }
112
113 lg2::error("[PWR] unexpected power state: {STATE}", "STATE", res);
114
115 co_return true;
116}
117
118// NOLINTBEGIN
119sdbusplus::async::task<> SoftwareManager::getInitialConfiguration(
120 const std::vector<std::string>& configurationInterfaces)
121// NOLINTEND
122{
123 auto client = sdbusplus::client::xyz::openbmc_project::ObjectMapper<>(ctx)
124 .service("xyz.openbmc_project.ObjectMapper")
125 .path("/xyz/openbmc_project/object_mapper");
126
127 auto res =
128 co_await client.get_sub_tree("/xyz/openbmc_project/inventory", 0, {});
129
130 for (auto& iface : configurationInterfaces)
131 {
132 lg2::debug("[config] looking for dbus interface {INTF}", "INTF", iface);
133 }
134
135 for (auto& [path, v] : res)
136 {
137 for (auto& [service, interfaceNames] : v)
138 {
139 std::string interfaceFound;
140
141 for (std::string& interfaceName : interfaceNames)
142 {
143 for (auto& iface : configurationInterfaces)
144 {
145 if (interfaceName == iface)
146 {
147 interfaceFound = interfaceName;
148 }
149 }
150 }
151
152 if (interfaceFound.empty())
153 {
154 continue;
155 }
156
157 lg2::debug(
158 "[config] found configuration interface at {SERVICE}, {OBJPATH}",
159 "SERVICE", service, "OBJPATH", path);
160
161 std::optional<uint64_t> optVendorIANA =
162 co_await SoftwareManager::dbusGetRequiredProperty<uint64_t>(
163 service, path, interfaceFound, "VendorIANA");
164
165 std::optional<std::string> optCompatible =
166 co_await SoftwareManager::dbusGetRequiredProperty<std::string>(
167 service, path, interfaceFound, "Compatible");
168
169 std::optional<std::string> optEMConfigType =
170 co_await SoftwareManager::dbusGetRequiredProperty<std::string>(
171 service, path, interfaceFound, "Type");
172
173 std::optional<std::string> optEMConfigName =
174 co_await SoftwareManager::dbusGetRequiredProperty<std::string>(
175 service, path, interfaceFound, "Name");
176
177 if (!optVendorIANA.has_value() || !optCompatible.has_value() ||
178 !optEMConfigType.has_value() || !optEMConfigName.has_value())
179 {
180 continue;
181 }
182
183 DeviceConfig config(optVendorIANA.value(), optCompatible.value(),
184 optEMConfigType.value(),
185 optEMConfigName.value());
186
187 co_await getInitialConfigurationSingleDevice(service, path, config);
188 }
189 }
190
191 lg2::debug("[config] done with initial configuration");
192
193 setupBusName();
194}