blob: 41352da366427309145754dc0225cc16dd59b131 [file] [log] [blame]
James Feistb49ac872019-05-21 15:12:01 -07001/*
2// Copyright (c) 2019 Intel Corporation
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15*/
16#pragma once
17
18#include "async_resp.hpp"
19
John Edward Broadbent7e860f12021-04-08 15:57:16 -070020#include <app.hpp>
James Feistb49ac872019-05-21 15:12:01 -070021#include <boost/algorithm/string/predicate.hpp>
22#include <boost/container/flat_set.hpp>
23#include <dbus_singleton.hpp>
Jonathan Doman1e1e5982021-06-11 09:36:17 -070024#include <dbus_utility.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050025
James Feistb49ac872019-05-21 15:12:01 -070026#include <variant>
27
28namespace redfish
29{
30
31struct HealthPopulate : std::enable_shared_from_this<HealthPopulate>
32{
zhanghch058d1b46d2021-04-01 11:18:24 +080033 HealthPopulate(const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn) :
Ed Tanous23a21a12020-07-25 04:45:05 +000034 asyncResp(asyncRespIn), jsonStatus(asyncResp->res.jsonValue["Status"])
Gunnar Mills1214b7e2020-06-04 10:11:30 -050035 {}
James Feist5bc2dc82019-10-22 14:33:16 -070036
zhanghch058d1b46d2021-04-01 11:18:24 +080037 HealthPopulate(const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn,
Gunnar Mills1214b7e2020-06-04 10:11:30 -050038 nlohmann::json& status) :
Ed Tanous23a21a12020-07-25 04:45:05 +000039 asyncResp(asyncRespIn),
James Feist5bc2dc82019-10-22 14:33:16 -070040 jsonStatus(status)
Gunnar Mills1214b7e2020-06-04 10:11:30 -050041 {}
James Feistb49ac872019-05-21 15:12:01 -070042
43 ~HealthPopulate()
44 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -050045 nlohmann::json& health = jsonStatus["Health"];
46 nlohmann::json& rollup = jsonStatus["HealthRollup"];
James Feistb49ac872019-05-21 15:12:01 -070047
48 health = "OK";
49 rollup = "OK";
50
Ed Tanous23a21a12020-07-25 04:45:05 +000051 for (const std::shared_ptr<HealthPopulate>& healthChild : children)
James Feist5bc2dc82019-10-22 14:33:16 -070052 {
Ed Tanous23a21a12020-07-25 04:45:05 +000053 healthChild->globalInventoryPath = globalInventoryPath;
54 healthChild->statuses = statuses;
James Feist5bc2dc82019-10-22 14:33:16 -070055 }
56
Gunnar Mills1214b7e2020-06-04 10:11:30 -050057 for (const auto& [path, interfaces] : statuses)
James Feistb49ac872019-05-21 15:12:01 -070058 {
59 bool isChild = false;
Karol Wojciechowski42cbb512021-07-28 17:12:20 +020060 bool isSelf = false;
61 if (selfPath)
62 {
63 if (boost::equals(path.str, *selfPath) ||
64 boost::starts_with(path.str, *selfPath + "/"))
65 {
66 isSelf = true;
67 }
68 }
James Feistb49ac872019-05-21 15:12:01 -070069
70 // managers inventory is all the inventory, don't skip any
James Feist35e257a2020-06-05 13:30:51 -070071 if (!isManagersHealth && !isSelf)
James Feistb49ac872019-05-21 15:12:01 -070072 {
73
74 // We only want to look at this association if either the path
75 // of this association is an inventory item, or one of the
76 // endpoints in this association is a child
77
Gunnar Mills1214b7e2020-06-04 10:11:30 -050078 for (const std::string& child : inventory)
James Feistb49ac872019-05-21 15:12:01 -070079 {
80 if (boost::starts_with(path.str, child))
81 {
82 isChild = true;
83 break;
84 }
85 }
86 if (!isChild)
87 {
88 auto assocIt =
89 interfaces.find("xyz.openbmc_project.Association");
90 if (assocIt == interfaces.end())
91 {
92 continue;
93 }
94 auto endpointsIt = assocIt->second.find("endpoints");
95 if (endpointsIt == assocIt->second.end())
96 {
97 BMCWEB_LOG_ERROR << "Illegal association at "
98 << path.str;
99 continue;
100 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500101 const std::vector<std::string>* endpoints =
James Feistb49ac872019-05-21 15:12:01 -0700102 std::get_if<std::vector<std::string>>(
103 &endpointsIt->second);
104 if (endpoints == nullptr)
105 {
106 BMCWEB_LOG_ERROR << "Illegal association at "
107 << path.str;
108 continue;
109 }
110 bool containsChild = false;
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500111 for (const std::string& endpoint : *endpoints)
James Feistb49ac872019-05-21 15:12:01 -0700112 {
113 if (std::find(inventory.begin(), inventory.end(),
114 endpoint) != inventory.end())
115 {
116 containsChild = true;
117 break;
118 }
119 }
120 if (!containsChild)
121 {
122 continue;
123 }
124 }
125 }
126
127 if (boost::starts_with(path.str, globalInventoryPath) &&
128 boost::ends_with(path.str, "critical"))
129 {
130 health = "Critical";
131 rollup = "Critical";
132 return;
133 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700134 if (boost::starts_with(path.str, globalInventoryPath) &&
135 boost::ends_with(path.str, "warning"))
James Feistb49ac872019-05-21 15:12:01 -0700136 {
137 health = "Warning";
138 if (rollup != "Critical")
139 {
140 rollup = "Warning";
141 }
142 }
143 else if (boost::ends_with(path.str, "critical"))
144 {
145 rollup = "Critical";
James Feist35e257a2020-06-05 13:30:51 -0700146 if (isSelf)
147 {
148 health = "Critical";
149 return;
150 }
James Feistb49ac872019-05-21 15:12:01 -0700151 }
152 else if (boost::ends_with(path.str, "warning"))
153 {
154 if (rollup != "Critical")
155 {
156 rollup = "Warning";
157 }
James Feist35e257a2020-06-05 13:30:51 -0700158
159 if (isSelf)
160 {
161 health = "Warning";
162 }
James Feistb49ac872019-05-21 15:12:01 -0700163 }
164 }
165 }
166
James Feist5bc2dc82019-10-22 14:33:16 -0700167 // this should only be called once per url, others should get updated by
168 // being added as children to the 'main' health object for the page
James Feistb49ac872019-05-21 15:12:01 -0700169 void populate()
170 {
James Feist9536a142019-11-21 09:02:32 -0800171 if (populated)
172 {
173 return;
174 }
175 populated = true;
James Feistb49ac872019-05-21 15:12:01 -0700176 getAllStatusAssociations();
177 getGlobalPath();
178 }
179
180 void getGlobalPath()
181 {
182 std::shared_ptr<HealthPopulate> self = shared_from_this();
183 crow::connections::systemBus->async_method_call(
184 [self](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500185 std::vector<std::string>& resp) {
James Feistb49ac872019-05-21 15:12:01 -0700186 if (ec || resp.size() != 1)
187 {
188 // no global item, or too many
189 return;
190 }
191 self->globalInventoryPath = std::move(resp[0]);
192 },
193 "xyz.openbmc_project.ObjectMapper",
194 "/xyz/openbmc_project/object_mapper",
Ed Tanous271584a2019-07-09 16:24:22 -0700195 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/", 0,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500196 std::array<const char*, 1>{
James Feistb49ac872019-05-21 15:12:01 -0700197 "xyz.openbmc_project.Inventory.Item.Global"});
198 }
199
200 void getAllStatusAssociations()
201 {
202 std::shared_ptr<HealthPopulate> self = shared_from_this();
203 crow::connections::systemBus->async_method_call(
204 [self](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500205 dbus::utility::ManagedObjectType& resp) {
James Feistb49ac872019-05-21 15:12:01 -0700206 if (ec)
207 {
208 return;
209 }
210 for (auto it = resp.begin(); it != resp.end();)
211 {
212 if (boost::ends_with(it->first.str, "critical") ||
213 boost::ends_with(it->first.str, "warning"))
214 {
215 it++;
216 continue;
217 }
218 it = resp.erase(it);
219 }
220 self->statuses = std::move(resp);
221 },
222 "xyz.openbmc_project.ObjectMapper", "/",
223 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
224 }
225
zhanghch058d1b46d2021-04-01 11:18:24 +0800226 std::shared_ptr<bmcweb::AsyncResp> asyncResp;
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500227 nlohmann::json& jsonStatus;
James Feist5bc2dc82019-10-22 14:33:16 -0700228
229 // we store pointers to other HealthPopulate items so we can update their
230 // members and reduce dbus calls. As we hold a shared_ptr to them, they get
231 // destroyed last, and they need not call populate()
232 std::vector<std::shared_ptr<HealthPopulate>> children;
233
James Feist35e257a2020-06-05 13:30:51 -0700234 // self is used if health is for an individual items status, as this is the
235 // 'lowest most' item, the rollup will equal the health
236 std::optional<std::string> selfPath;
237
James Feistb49ac872019-05-21 15:12:01 -0700238 std::vector<std::string> inventory;
239 bool isManagersHealth = false;
240 dbus::utility::ManagedObjectType statuses;
241 std::string globalInventoryPath = "-"; // default to illegal dbus path
James Feist9536a142019-11-21 09:02:32 -0800242 bool populated = false;
James Feistb49ac872019-05-21 15:12:01 -0700243};
Ed Tanous23a21a12020-07-25 04:45:05 +0000244} // namespace redfish