blob: 71da99ec015d5838b1823d54bb232e7f49714ec8 [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 {
Ed Tanous711ac7a2021-12-20 09:34:41 -080088 for (const auto& [interface, association] : interfaces)
James Feistb49ac872019-05-21 15:12:01 -070089 {
Ed Tanous711ac7a2021-12-20 09:34:41 -080090 if (interface != "xyz.openbmc_project.Association")
James Feistb49ac872019-05-21 15:12:01 -070091 {
Ed Tanous711ac7a2021-12-20 09:34:41 -080092 continue;
James Feistb49ac872019-05-21 15:12:01 -070093 }
Ed Tanous711ac7a2021-12-20 09:34:41 -080094 for (const auto& [name, value] : association)
95 {
96 if (name != "endpoints")
97 {
98 continue;
99 }
100
101 const std::vector<std::string>* endpoints =
102 std::get_if<std::vector<std::string>>(&value);
103 if (endpoints == nullptr)
104 {
105 BMCWEB_LOG_ERROR << "Illegal association at "
106 << path.str;
107 continue;
108 }
109 bool containsChild = false;
110 for (const std::string& endpoint : *endpoints)
111 {
112 if (std::find(inventory.begin(),
113 inventory.end(),
114 endpoint) != inventory.end())
115 {
116 containsChild = true;
117 break;
118 }
119 }
120 if (!containsChild)
121 {
122 continue;
123 }
124 }
James Feistb49ac872019-05-21 15:12:01 -0700125 }
126 }
127 }
128
129 if (boost::starts_with(path.str, globalInventoryPath) &&
130 boost::ends_with(path.str, "critical"))
131 {
132 health = "Critical";
133 rollup = "Critical";
134 return;
135 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700136 if (boost::starts_with(path.str, globalInventoryPath) &&
137 boost::ends_with(path.str, "warning"))
James Feistb49ac872019-05-21 15:12:01 -0700138 {
139 health = "Warning";
140 if (rollup != "Critical")
141 {
142 rollup = "Warning";
143 }
144 }
145 else if (boost::ends_with(path.str, "critical"))
146 {
147 rollup = "Critical";
James Feist35e257a2020-06-05 13:30:51 -0700148 if (isSelf)
149 {
150 health = "Critical";
151 return;
152 }
James Feistb49ac872019-05-21 15:12:01 -0700153 }
154 else if (boost::ends_with(path.str, "warning"))
155 {
156 if (rollup != "Critical")
157 {
158 rollup = "Warning";
159 }
James Feist35e257a2020-06-05 13:30:51 -0700160
161 if (isSelf)
162 {
163 health = "Warning";
164 }
James Feistb49ac872019-05-21 15:12:01 -0700165 }
166 }
167 }
168
James Feist5bc2dc82019-10-22 14:33:16 -0700169 // this should only be called once per url, others should get updated by
170 // being added as children to the 'main' health object for the page
James Feistb49ac872019-05-21 15:12:01 -0700171 void populate()
172 {
James Feist9536a142019-11-21 09:02:32 -0800173 if (populated)
174 {
175 return;
176 }
177 populated = true;
James Feistb49ac872019-05-21 15:12:01 -0700178 getAllStatusAssociations();
179 getGlobalPath();
180 }
181
182 void getGlobalPath()
183 {
184 std::shared_ptr<HealthPopulate> self = shared_from_this();
185 crow::connections::systemBus->async_method_call(
186 [self](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500187 std::vector<std::string>& resp) {
James Feistb49ac872019-05-21 15:12:01 -0700188 if (ec || resp.size() != 1)
189 {
190 // no global item, or too many
191 return;
192 }
193 self->globalInventoryPath = std::move(resp[0]);
194 },
195 "xyz.openbmc_project.ObjectMapper",
196 "/xyz/openbmc_project/object_mapper",
Ed Tanous271584a2019-07-09 16:24:22 -0700197 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/", 0,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500198 std::array<const char*, 1>{
James Feistb49ac872019-05-21 15:12:01 -0700199 "xyz.openbmc_project.Inventory.Item.Global"});
200 }
201
202 void getAllStatusAssociations()
203 {
204 std::shared_ptr<HealthPopulate> self = shared_from_this();
205 crow::connections::systemBus->async_method_call(
206 [self](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500207 dbus::utility::ManagedObjectType& resp) {
James Feistb49ac872019-05-21 15:12:01 -0700208 if (ec)
209 {
210 return;
211 }
212 for (auto it = resp.begin(); it != resp.end();)
213 {
214 if (boost::ends_with(it->first.str, "critical") ||
215 boost::ends_with(it->first.str, "warning"))
216 {
217 it++;
218 continue;
219 }
220 it = resp.erase(it);
221 }
222 self->statuses = std::move(resp);
223 },
224 "xyz.openbmc_project.ObjectMapper", "/",
225 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
226 }
227
zhanghch058d1b46d2021-04-01 11:18:24 +0800228 std::shared_ptr<bmcweb::AsyncResp> asyncResp;
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500229 nlohmann::json& jsonStatus;
James Feist5bc2dc82019-10-22 14:33:16 -0700230
231 // we store pointers to other HealthPopulate items so we can update their
232 // members and reduce dbus calls. As we hold a shared_ptr to them, they get
233 // destroyed last, and they need not call populate()
234 std::vector<std::shared_ptr<HealthPopulate>> children;
235
James Feist35e257a2020-06-05 13:30:51 -0700236 // self is used if health is for an individual items status, as this is the
237 // 'lowest most' item, the rollup will equal the health
238 std::optional<std::string> selfPath;
239
James Feistb49ac872019-05-21 15:12:01 -0700240 std::vector<std::string> inventory;
241 bool isManagersHealth = false;
242 dbus::utility::ManagedObjectType statuses;
243 std::string globalInventoryPath = "-"; // default to illegal dbus path
James Feist9536a142019-11-21 09:02:32 -0800244 bool populated = false;
James Feistb49ac872019-05-21 15:12:01 -0700245};
Ed Tanous23a21a12020-07-25 04:45:05 +0000246} // namespace redfish