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