blob: 7942be9b1abe61a2b097aa85952daea1ec2f07d6 [file] [log] [blame]
Faisal Awadafe5b5c62025-03-22 10:50:01 -05001#include "validator.hpp"
2
3#include "model.hpp"
4
5#include <phosphor-logging/lg2.hpp>
6
7#include <iostream>
8
9namespace validator
10{
11using namespace phosphor::power::util;
12constexpr auto supportedConfIntf =
13 "xyz.openbmc_project.Configuration.SupportedConfiguration";
14const auto IBMCFFPSInterface =
15 "xyz.openbmc_project.Configuration.IBMCFFPSConnector";
16const auto objectPath = "/";
17
18bool PSUUpdateValidator::areAllPsuSameModel()
19{
20 try
21 {
22 targetPsuModel = model::getModel(bus, psuPath);
23 psuPaths = getPSUInventoryPaths(bus);
24 for (const auto& path : psuPaths)
25 {
26 auto thisPsuModel = model::getModel(bus, path);
27 // All PSUs must have same model
28 if (targetPsuModel != thisPsuModel)
29 {
30 lg2::error(
31 "PSU models do not match, targetPsuModel= {TARGET}, thisPsuModel= {THISPSU}",
32 "TARGET", targetPsuModel, "THISPSU", thisPsuModel);
33 return false;
34 }
35 }
36 }
37 catch (const std::exception& e)
38 {
39 lg2::error("Failed to get all PSUs from EM, error {ERROR}", "ERROR", e);
40 return false;
41 }
42 return true;
43}
44
45bool PSUUpdateValidator::countPresentPsus()
46{
47 auto psuPaths = getPSUInventoryPaths(bus);
48 for (const auto& path : psuPaths)
49 {
50 auto present = false;
51 try
52 {
53 getProperty(INVENTORY_IFACE, PRESENT_PROP, path,
54 INVENTORY_MGR_IFACE, bus, present);
55 if (present)
56 {
57 if (!isItFunctional(path))
58 {
59 lg2::error("PSU {PATH} is not functional", "PATH", path);
60 return false;
61 }
62
63 presentPsuCount++;
64 }
65 }
66 catch (const std::exception& e)
67 {
68 lg2::error("Failed to get PSU present status, error {ERR} ", "ERR",
69 e);
70 return false;
71 }
72 }
73 return true;
74}
75
76bool PSUUpdateValidator::getRequiredPsus()
77{
78 try
79 {
80 supportedObjects = getSubTree(bus, objectPath, supportedConfIntf, 0);
81 }
82 catch (std::exception& e)
83 {
84 lg2::error("Failed to retrieve supported configuration");
85 return false;
86 }
87 for (const auto& [objPath, services] : supportedObjects)
88 {
89 if (objPath.empty() || services.empty())
90 {
91 continue;
92 }
93
94 std::string service = services.begin()->first;
95 try
96 {
97 properties =
98 getAllProperties(bus, objPath, supportedConfIntf, service);
99 }
100 catch (const std::exception& e)
101 {
102 lg2::error(
103 "Failed to get all PSU {PSUPATH} properties error: {ERR}",
104 "PSUPATH", objPath, "ERR", e);
105 return false;
106 }
107 auto propertyModel = properties.find("SupportedModel");
108 if (propertyModel == properties.end())
109 {
110 continue;
111 }
112 try
113 {
114 auto supportedModel = std::get<std::string>(propertyModel->second);
115 if ((supportedModel.empty()) || (supportedModel != targetPsuModel))
116 {
117 continue;
118 }
119 }
120 catch (const std::bad_variant_access& e)
121 {
122 lg2::error("Failed to get supportedModel, error: {ERR}", "ERR", e);
123 }
124
125 try
126 {
127 auto redundantCountProp = properties.find("RedundantCount");
128 if (redundantCountProp != properties.end())
129 {
130 redundantCount = static_cast<int>(
131 std::get<uint64_t>(redundantCountProp->second));
132 break;
133 }
134 }
135 catch (const std::bad_variant_access& e)
136 {
137 lg2::error("Redundant type mismatch, error: {ERR}", "ERR", e);
138 }
139 }
140 return true;
141}
142
143bool PSUUpdateValidator::isItFunctional(const std::string& path)
144{
145 try
146 {
147 bool isFunctional = false;
148 getProperty(OPERATIONAL_STATE_IFACE, FUNCTIONAL_PROP, path,
149 INVENTORY_MGR_IFACE, bus, isFunctional);
150 return isFunctional;
151 }
152 catch (const std::exception& e)
153 {
154 lg2::error("Failed to get PSU fault status, error {ERR} ", "ERR", e);
155 return false;
156 }
157}
158
159bool PSUUpdateValidator::validToUpdate()
160{
161 if (areAllPsuSameModel() && countPresentPsus() && getRequiredPsus())
162 {
163 if (presentPsuCount >= redundantCount)
164 {
165 return true;
166 }
167 }
168 return false;
169}
170} // namespace validator