1*6b1b0ea9SAsmitha Karunanithi #include "hostname_manager.hpp"
2*6b1b0ea9SAsmitha Karunanithi
3*6b1b0ea9SAsmitha Karunanithi #include "network_manager.hpp"
4*6b1b0ea9SAsmitha Karunanithi
5*6b1b0ea9SAsmitha Karunanithi #include <phosphor-logging/elog-errors.hpp>
6*6b1b0ea9SAsmitha Karunanithi #include <phosphor-logging/lg2.hpp>
7*6b1b0ea9SAsmitha Karunanithi #include <sdbusplus/bus.hpp>
8*6b1b0ea9SAsmitha Karunanithi #include <stdplus/pinned.hpp>
9*6b1b0ea9SAsmitha Karunanithi #include <xyz/openbmc_project/Common/error.hpp>
10*6b1b0ea9SAsmitha Karunanithi
11*6b1b0ea9SAsmitha Karunanithi #include <filesystem>
12*6b1b0ea9SAsmitha Karunanithi #include <fstream>
13*6b1b0ea9SAsmitha Karunanithi #include <string>
14*6b1b0ea9SAsmitha Karunanithi
15*6b1b0ea9SAsmitha Karunanithi namespace phosphor
16*6b1b0ea9SAsmitha Karunanithi {
17*6b1b0ea9SAsmitha Karunanithi namespace network
18*6b1b0ea9SAsmitha Karunanithi {
19*6b1b0ea9SAsmitha Karunanithi
20*6b1b0ea9SAsmitha Karunanithi using namespace phosphor::logging;
21*6b1b0ea9SAsmitha Karunanithi using namespace sdbusplus::xyz::openbmc_project::Common::Error;
22*6b1b0ea9SAsmitha Karunanithi
23*6b1b0ea9SAsmitha Karunanithi static constexpr const char* mapperBusName = "xyz.openbmc_project.ObjectMapper";
24*6b1b0ea9SAsmitha Karunanithi static constexpr const char* mapperObjPath =
25*6b1b0ea9SAsmitha Karunanithi "/xyz/openbmc_project/object_mapper";
26*6b1b0ea9SAsmitha Karunanithi static constexpr const char* mapperIntf = "xyz.openbmc_project.ObjectMapper";
27*6b1b0ea9SAsmitha Karunanithi static constexpr const char* inventoryRoot = "/xyz/openbmc_project/inventory";
28*6b1b0ea9SAsmitha Karunanithi static constexpr const char* bmcItemIntf =
29*6b1b0ea9SAsmitha Karunanithi "xyz.openbmc_project.Inventory.Item.Bmc";
30*6b1b0ea9SAsmitha Karunanithi static constexpr const char* assetIntf =
31*6b1b0ea9SAsmitha Karunanithi "xyz.openbmc_project.Inventory.Decorator.Asset";
32*6b1b0ea9SAsmitha Karunanithi static constexpr const char* networkItemIntf =
33*6b1b0ea9SAsmitha Karunanithi "xyz.openbmc_project.Inventory.Item.NetworkInterface";
34*6b1b0ea9SAsmitha Karunanithi static constexpr const char* propIntf = "org.freedesktop.DBus.Properties";
35*6b1b0ea9SAsmitha Karunanithi static constexpr const char* hostnamedBusName = "org.freedesktop.hostname1";
36*6b1b0ea9SAsmitha Karunanithi static constexpr const char* hostnamedObjPath = "/org/freedesktop/hostname1";
37*6b1b0ea9SAsmitha Karunanithi static constexpr const char* hostnamedIntf = "org.freedesktop.hostname1";
38*6b1b0ea9SAsmitha Karunanithi
HostnameManager(stdplus::PinnedRef<sdbusplus::bus_t> bus,stdplus::PinnedRef<Manager> manager)39*6b1b0ea9SAsmitha Karunanithi HostnameManager::HostnameManager(stdplus::PinnedRef<sdbusplus::bus_t> bus,
40*6b1b0ea9SAsmitha Karunanithi stdplus::PinnedRef<Manager> manager) :
41*6b1b0ea9SAsmitha Karunanithi bus(bus), manager(manager)
42*6b1b0ea9SAsmitha Karunanithi {}
43*6b1b0ea9SAsmitha Karunanithi
initialize()44*6b1b0ea9SAsmitha Karunanithi void HostnameManager::initialize()
45*6b1b0ea9SAsmitha Karunanithi {
46*6b1b0ea9SAsmitha Karunanithi if (!isFirstBoot())
47*6b1b0ea9SAsmitha Karunanithi {
48*6b1b0ea9SAsmitha Karunanithi lg2::info("Hostname already set on previous boot, skipping");
49*6b1b0ea9SAsmitha Karunanithi return;
50*6b1b0ea9SAsmitha Karunanithi }
51*6b1b0ea9SAsmitha Karunanithi
52*6b1b0ea9SAsmitha Karunanithi lg2::info("First boot detected, setting unique hostname");
53*6b1b0ea9SAsmitha Karunanithi setUniqueHostname();
54*6b1b0ea9SAsmitha Karunanithi markHostnameSet();
55*6b1b0ea9SAsmitha Karunanithi }
56*6b1b0ea9SAsmitha Karunanithi
isFirstBoot() const57*6b1b0ea9SAsmitha Karunanithi bool HostnameManager::isFirstBoot() const
58*6b1b0ea9SAsmitha Karunanithi {
59*6b1b0ea9SAsmitha Karunanithi return !std::filesystem::exists(firstBootFile);
60*6b1b0ea9SAsmitha Karunanithi }
61*6b1b0ea9SAsmitha Karunanithi
markHostnameSet()62*6b1b0ea9SAsmitha Karunanithi void HostnameManager::markHostnameSet()
63*6b1b0ea9SAsmitha Karunanithi {
64*6b1b0ea9SAsmitha Karunanithi try
65*6b1b0ea9SAsmitha Karunanithi {
66*6b1b0ea9SAsmitha Karunanithi // Create parent directories if they don't exist
67*6b1b0ea9SAsmitha Karunanithi std::filesystem::path firstBootFilePath(firstBootFile);
68*6b1b0ea9SAsmitha Karunanithi std::filesystem::create_directories(firstBootFilePath.parent_path());
69*6b1b0ea9SAsmitha Karunanithi
70*6b1b0ea9SAsmitha Karunanithi std::ofstream file(firstBootFile);
71*6b1b0ea9SAsmitha Karunanithi if (!file)
72*6b1b0ea9SAsmitha Karunanithi {
73*6b1b0ea9SAsmitha Karunanithi lg2::error("Failed to create firstBoot file: {PATH}", "PATH",
74*6b1b0ea9SAsmitha Karunanithi firstBootFile);
75*6b1b0ea9SAsmitha Karunanithi }
76*6b1b0ea9SAsmitha Karunanithi }
77*6b1b0ea9SAsmitha Karunanithi catch (const std::exception& e)
78*6b1b0ea9SAsmitha Karunanithi {
79*6b1b0ea9SAsmitha Karunanithi lg2::error("Exception creating firstBoot file: {ERROR}", "ERROR", e);
80*6b1b0ea9SAsmitha Karunanithi }
81*6b1b0ea9SAsmitha Karunanithi }
82*6b1b0ea9SAsmitha Karunanithi
getBmcSerialNumber()83*6b1b0ea9SAsmitha Karunanithi std::string HostnameManager::getBmcSerialNumber()
84*6b1b0ea9SAsmitha Karunanithi {
85*6b1b0ea9SAsmitha Karunanithi try
86*6b1b0ea9SAsmitha Karunanithi {
87*6b1b0ea9SAsmitha Karunanithi // Get BMC item path from inventory
88*6b1b0ea9SAsmitha Karunanithi auto method = bus.get().new_method_call(mapperBusName, mapperObjPath,
89*6b1b0ea9SAsmitha Karunanithi mapperIntf, "GetSubTree");
90*6b1b0ea9SAsmitha Karunanithi method.append(inventoryRoot, 0, std::vector<std::string>{bmcItemIntf});
91*6b1b0ea9SAsmitha Karunanithi
92*6b1b0ea9SAsmitha Karunanithi auto reply = bus.get().call(method);
93*6b1b0ea9SAsmitha Karunanithi
94*6b1b0ea9SAsmitha Karunanithi std::map<std::string, std::map<std::string, std::vector<std::string>>>
95*6b1b0ea9SAsmitha Karunanithi response;
96*6b1b0ea9SAsmitha Karunanithi reply.read(response);
97*6b1b0ea9SAsmitha Karunanithi
98*6b1b0ea9SAsmitha Karunanithi if (response.empty())
99*6b1b0ea9SAsmitha Karunanithi {
100*6b1b0ea9SAsmitha Karunanithi lg2::warning("No BMC item found in inventory");
101*6b1b0ea9SAsmitha Karunanithi return "";
102*6b1b0ea9SAsmitha Karunanithi }
103*6b1b0ea9SAsmitha Karunanithi
104*6b1b0ea9SAsmitha Karunanithi // Get the first BMC item path
105*6b1b0ea9SAsmitha Karunanithi const auto& bmcPath = response.begin()->first;
106*6b1b0ea9SAsmitha Karunanithi const auto& serviceMap = response.begin()->second;
107*6b1b0ea9SAsmitha Karunanithi
108*6b1b0ea9SAsmitha Karunanithi if (serviceMap.empty())
109*6b1b0ea9SAsmitha Karunanithi {
110*6b1b0ea9SAsmitha Karunanithi lg2::warning("No service found for BMC item");
111*6b1b0ea9SAsmitha Karunanithi return "";
112*6b1b0ea9SAsmitha Karunanithi }
113*6b1b0ea9SAsmitha Karunanithi
114*6b1b0ea9SAsmitha Karunanithi const auto& serviceName = serviceMap.begin()->first;
115*6b1b0ea9SAsmitha Karunanithi
116*6b1b0ea9SAsmitha Karunanithi // Get SerialNumber property
117*6b1b0ea9SAsmitha Karunanithi auto propMethod = bus.get().new_method_call(
118*6b1b0ea9SAsmitha Karunanithi serviceName.c_str(), bmcPath.c_str(), propIntf, "Get");
119*6b1b0ea9SAsmitha Karunanithi propMethod.append(assetIntf, "SerialNumber");
120*6b1b0ea9SAsmitha Karunanithi
121*6b1b0ea9SAsmitha Karunanithi auto propReply = bus.get().call(propMethod);
122*6b1b0ea9SAsmitha Karunanithi std::variant<std::string> serialNumber;
123*6b1b0ea9SAsmitha Karunanithi propReply.read(serialNumber);
124*6b1b0ea9SAsmitha Karunanithi
125*6b1b0ea9SAsmitha Karunanithi std::string sn = std::get<std::string>(serialNumber);
126*6b1b0ea9SAsmitha Karunanithi if (sn.empty())
127*6b1b0ea9SAsmitha Karunanithi {
128*6b1b0ea9SAsmitha Karunanithi lg2::warning("BMC Serial Number is empty");
129*6b1b0ea9SAsmitha Karunanithi }
130*6b1b0ea9SAsmitha Karunanithi else
131*6b1b0ea9SAsmitha Karunanithi {
132*6b1b0ea9SAsmitha Karunanithi lg2::info("Retrieved BMC Serial Number: {SN}", "SN", sn);
133*6b1b0ea9SAsmitha Karunanithi }
134*6b1b0ea9SAsmitha Karunanithi
135*6b1b0ea9SAsmitha Karunanithi return sn;
136*6b1b0ea9SAsmitha Karunanithi }
137*6b1b0ea9SAsmitha Karunanithi catch (const std::exception& e)
138*6b1b0ea9SAsmitha Karunanithi {
139*6b1b0ea9SAsmitha Karunanithi lg2::error("Failed to get BMC serial number: {ERROR}", "ERROR", e);
140*6b1b0ea9SAsmitha Karunanithi return "";
141*6b1b0ea9SAsmitha Karunanithi }
142*6b1b0ea9SAsmitha Karunanithi }
143*6b1b0ea9SAsmitha Karunanithi
getMacAddress()144*6b1b0ea9SAsmitha Karunanithi std::string HostnameManager::getMacAddress()
145*6b1b0ea9SAsmitha Karunanithi {
146*6b1b0ea9SAsmitha Karunanithi try
147*6b1b0ea9SAsmitha Karunanithi {
148*6b1b0ea9SAsmitha Karunanithi auto method = bus.get().new_method_call(mapperBusName, mapperObjPath,
149*6b1b0ea9SAsmitha Karunanithi mapperIntf, "GetSubTree");
150*6b1b0ea9SAsmitha Karunanithi method.append(inventoryRoot, 0,
151*6b1b0ea9SAsmitha Karunanithi std::vector<std::string>{networkItemIntf});
152*6b1b0ea9SAsmitha Karunanithi
153*6b1b0ea9SAsmitha Karunanithi auto reply = bus.get().call(method);
154*6b1b0ea9SAsmitha Karunanithi
155*6b1b0ea9SAsmitha Karunanithi std::map<std::string, std::map<std::string, std::vector<std::string>>>
156*6b1b0ea9SAsmitha Karunanithi response;
157*6b1b0ea9SAsmitha Karunanithi reply.read(response);
158*6b1b0ea9SAsmitha Karunanithi
159*6b1b0ea9SAsmitha Karunanithi if (response.empty())
160*6b1b0ea9SAsmitha Karunanithi {
161*6b1b0ea9SAsmitha Karunanithi lg2::warning("No network interface found in inventory");
162*6b1b0ea9SAsmitha Karunanithi return "";
163*6b1b0ea9SAsmitha Karunanithi }
164*6b1b0ea9SAsmitha Karunanithi
165*6b1b0ea9SAsmitha Karunanithi // Get the first network interface path
166*6b1b0ea9SAsmitha Karunanithi const auto& netPath = response.begin()->first;
167*6b1b0ea9SAsmitha Karunanithi const auto& serviceMap = response.begin()->second;
168*6b1b0ea9SAsmitha Karunanithi
169*6b1b0ea9SAsmitha Karunanithi if (serviceMap.empty())
170*6b1b0ea9SAsmitha Karunanithi {
171*6b1b0ea9SAsmitha Karunanithi lg2::warning("No service found for network interface");
172*6b1b0ea9SAsmitha Karunanithi return "";
173*6b1b0ea9SAsmitha Karunanithi }
174*6b1b0ea9SAsmitha Karunanithi
175*6b1b0ea9SAsmitha Karunanithi const auto& serviceName = serviceMap.begin()->first;
176*6b1b0ea9SAsmitha Karunanithi
177*6b1b0ea9SAsmitha Karunanithi // Get MACAddress property
178*6b1b0ea9SAsmitha Karunanithi auto propMethod = bus.get().new_method_call(
179*6b1b0ea9SAsmitha Karunanithi serviceName.c_str(), netPath.c_str(), propIntf, "Get");
180*6b1b0ea9SAsmitha Karunanithi propMethod.append(networkItemIntf, "MACAddress");
181*6b1b0ea9SAsmitha Karunanithi
182*6b1b0ea9SAsmitha Karunanithi auto propReply = bus.get().call(propMethod);
183*6b1b0ea9SAsmitha Karunanithi std::variant<std::string> macAddress;
184*6b1b0ea9SAsmitha Karunanithi propReply.read(macAddress);
185*6b1b0ea9SAsmitha Karunanithi
186*6b1b0ea9SAsmitha Karunanithi std::string mac = std::get<std::string>(macAddress);
187*6b1b0ea9SAsmitha Karunanithi if (mac.empty())
188*6b1b0ea9SAsmitha Karunanithi {
189*6b1b0ea9SAsmitha Karunanithi lg2::warning("MAC Address is empty");
190*6b1b0ea9SAsmitha Karunanithi }
191*6b1b0ea9SAsmitha Karunanithi else
192*6b1b0ea9SAsmitha Karunanithi {
193*6b1b0ea9SAsmitha Karunanithi lg2::info("Retrieved MAC Address: {MAC}", "MAC", mac);
194*6b1b0ea9SAsmitha Karunanithi }
195*6b1b0ea9SAsmitha Karunanithi
196*6b1b0ea9SAsmitha Karunanithi return mac;
197*6b1b0ea9SAsmitha Karunanithi }
198*6b1b0ea9SAsmitha Karunanithi catch (const std::exception& e)
199*6b1b0ea9SAsmitha Karunanithi {
200*6b1b0ea9SAsmitha Karunanithi lg2::error("Failed to get MAC address: {ERROR}", "ERROR", e);
201*6b1b0ea9SAsmitha Karunanithi return "";
202*6b1b0ea9SAsmitha Karunanithi }
203*6b1b0ea9SAsmitha Karunanithi }
204*6b1b0ea9SAsmitha Karunanithi
getCurrentHostname()205*6b1b0ea9SAsmitha Karunanithi std::string HostnameManager::getCurrentHostname()
206*6b1b0ea9SAsmitha Karunanithi {
207*6b1b0ea9SAsmitha Karunanithi try
208*6b1b0ea9SAsmitha Karunanithi {
209*6b1b0ea9SAsmitha Karunanithi auto method = bus.get().new_method_call(
210*6b1b0ea9SAsmitha Karunanithi hostnamedBusName, hostnamedObjPath, propIntf, "Get");
211*6b1b0ea9SAsmitha Karunanithi method.append(hostnamedIntf, "Hostname");
212*6b1b0ea9SAsmitha Karunanithi
213*6b1b0ea9SAsmitha Karunanithi auto reply = bus.get().call(method);
214*6b1b0ea9SAsmitha Karunanithi std::variant<std::string> hostname;
215*6b1b0ea9SAsmitha Karunanithi reply.read(hostname);
216*6b1b0ea9SAsmitha Karunanithi
217*6b1b0ea9SAsmitha Karunanithi return std::get<std::string>(hostname);
218*6b1b0ea9SAsmitha Karunanithi }
219*6b1b0ea9SAsmitha Karunanithi catch (const std::exception& e)
220*6b1b0ea9SAsmitha Karunanithi {
221*6b1b0ea9SAsmitha Karunanithi lg2::error("Failed to get current hostname: {ERROR}", "ERROR", e);
222*6b1b0ea9SAsmitha Karunanithi return "localhost";
223*6b1b0ea9SAsmitha Karunanithi }
224*6b1b0ea9SAsmitha Karunanithi }
225*6b1b0ea9SAsmitha Karunanithi
setHostname(const std::string & hostname)226*6b1b0ea9SAsmitha Karunanithi bool HostnameManager::setHostname(const std::string& hostname)
227*6b1b0ea9SAsmitha Karunanithi {
228*6b1b0ea9SAsmitha Karunanithi try
229*6b1b0ea9SAsmitha Karunanithi {
230*6b1b0ea9SAsmitha Karunanithi auto method =
231*6b1b0ea9SAsmitha Karunanithi bus.get().new_method_call(hostnamedBusName, hostnamedObjPath,
232*6b1b0ea9SAsmitha Karunanithi hostnamedIntf, "SetStaticHostname");
233*6b1b0ea9SAsmitha Karunanithi method.append(hostname, false);
234*6b1b0ea9SAsmitha Karunanithi
235*6b1b0ea9SAsmitha Karunanithi bus.get().call(method);
236*6b1b0ea9SAsmitha Karunanithi lg2::info("Successfully set hostname to: {HOSTNAME}", "HOSTNAME",
237*6b1b0ea9SAsmitha Karunanithi hostname);
238*6b1b0ea9SAsmitha Karunanithi return true;
239*6b1b0ea9SAsmitha Karunanithi }
240*6b1b0ea9SAsmitha Karunanithi catch (const std::exception& e)
241*6b1b0ea9SAsmitha Karunanithi {
242*6b1b0ea9SAsmitha Karunanithi lg2::error("Failed to set hostname to {HOSTNAME}: {ERROR}", "HOSTNAME",
243*6b1b0ea9SAsmitha Karunanithi hostname, "ERROR", e);
244*6b1b0ea9SAsmitha Karunanithi return false;
245*6b1b0ea9SAsmitha Karunanithi }
246*6b1b0ea9SAsmitha Karunanithi }
247*6b1b0ea9SAsmitha Karunanithi
setUniqueHostname()248*6b1b0ea9SAsmitha Karunanithi void HostnameManager::setUniqueHostname()
249*6b1b0ea9SAsmitha Karunanithi {
250*6b1b0ea9SAsmitha Karunanithi std::string currentHostname = getCurrentHostname();
251*6b1b0ea9SAsmitha Karunanithi std::string uniqueSuffix;
252*6b1b0ea9SAsmitha Karunanithi
253*6b1b0ea9SAsmitha Karunanithi // Try to get BMC serial number first
254*6b1b0ea9SAsmitha Karunanithi std::string serialNumber = getBmcSerialNumber();
255*6b1b0ea9SAsmitha Karunanithi if (!serialNumber.empty())
256*6b1b0ea9SAsmitha Karunanithi {
257*6b1b0ea9SAsmitha Karunanithi uniqueSuffix = serialNumber;
258*6b1b0ea9SAsmitha Karunanithi lg2::info("Using BMC Serial Number for unique hostname");
259*6b1b0ea9SAsmitha Karunanithi }
260*6b1b0ea9SAsmitha Karunanithi else
261*6b1b0ea9SAsmitha Karunanithi {
262*6b1b0ea9SAsmitha Karunanithi // Fallback to MAC address
263*6b1b0ea9SAsmitha Karunanithi lg2::warning(
264*6b1b0ea9SAsmitha Karunanithi "BMC Serial Number not available, falling back to MAC address");
265*6b1b0ea9SAsmitha Karunanithi std::string macAddress = getMacAddress();
266*6b1b0ea9SAsmitha Karunanithi if (!macAddress.empty())
267*6b1b0ea9SAsmitha Karunanithi {
268*6b1b0ea9SAsmitha Karunanithi uniqueSuffix = macAddress;
269*6b1b0ea9SAsmitha Karunanithi lg2::info("Using MAC Address for unique hostname");
270*6b1b0ea9SAsmitha Karunanithi }
271*6b1b0ea9SAsmitha Karunanithi else
272*6b1b0ea9SAsmitha Karunanithi {
273*6b1b0ea9SAsmitha Karunanithi lg2::error(
274*6b1b0ea9SAsmitha Karunanithi "Neither Serial Number nor MAC Address available, cannot set unique hostname");
275*6b1b0ea9SAsmitha Karunanithi return;
276*6b1b0ea9SAsmitha Karunanithi }
277*6b1b0ea9SAsmitha Karunanithi }
278*6b1b0ea9SAsmitha Karunanithi
279*6b1b0ea9SAsmitha Karunanithi // Construct and set unique hostname
280*6b1b0ea9SAsmitha Karunanithi std::string newHostname = currentHostname + "-" + uniqueSuffix;
281*6b1b0ea9SAsmitha Karunanithi
282*6b1b0ea9SAsmitha Karunanithi if (setHostname(newHostname))
283*6b1b0ea9SAsmitha Karunanithi {
284*6b1b0ea9SAsmitha Karunanithi lg2::info("Unique hostname set successfully: {HOSTNAME}", "HOSTNAME",
285*6b1b0ea9SAsmitha Karunanithi newHostname);
286*6b1b0ea9SAsmitha Karunanithi }
287*6b1b0ea9SAsmitha Karunanithi else
288*6b1b0ea9SAsmitha Karunanithi {
289*6b1b0ea9SAsmitha Karunanithi lg2::error("Failed to set unique hostname");
290*6b1b0ea9SAsmitha Karunanithi }
291*6b1b0ea9SAsmitha Karunanithi }
292*6b1b0ea9SAsmitha Karunanithi
293*6b1b0ea9SAsmitha Karunanithi } // namespace network
294*6b1b0ea9SAsmitha Karunanithi } // namespace phosphor
295