blob: 510b8954cae3b25ce978959fa62a62f8058dedab [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>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050024
James Feistb49ac872019-05-21 15:12:01 -070025#include <variant>
26
27namespace redfish
28{
29
30struct HealthPopulate : std::enable_shared_from_this<HealthPopulate>
31{
zhanghch058d1b46d2021-04-01 11:18:24 +080032 HealthPopulate(const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn) :
Ed Tanous23a21a12020-07-25 04:45:05 +000033 asyncResp(asyncRespIn), jsonStatus(asyncResp->res.jsonValue["Status"])
Gunnar Mills1214b7e2020-06-04 10:11:30 -050034 {}
James Feist5bc2dc82019-10-22 14:33:16 -070035
zhanghch058d1b46d2021-04-01 11:18:24 +080036 HealthPopulate(const std::shared_ptr<bmcweb::AsyncResp>& asyncRespIn,
Gunnar Mills1214b7e2020-06-04 10:11:30 -050037 nlohmann::json& status) :
Ed Tanous23a21a12020-07-25 04:45:05 +000038 asyncResp(asyncRespIn),
James Feist5bc2dc82019-10-22 14:33:16 -070039 jsonStatus(status)
Gunnar Mills1214b7e2020-06-04 10:11:30 -050040 {}
James Feistb49ac872019-05-21 15:12:01 -070041
42 ~HealthPopulate()
43 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -050044 nlohmann::json& health = jsonStatus["Health"];
45 nlohmann::json& rollup = jsonStatus["HealthRollup"];
James Feistb49ac872019-05-21 15:12:01 -070046
47 health = "OK";
48 rollup = "OK";
49
Ed Tanous23a21a12020-07-25 04:45:05 +000050 for (const std::shared_ptr<HealthPopulate>& healthChild : children)
James Feist5bc2dc82019-10-22 14:33:16 -070051 {
Ed Tanous23a21a12020-07-25 04:45:05 +000052 healthChild->globalInventoryPath = globalInventoryPath;
53 healthChild->statuses = statuses;
James Feist5bc2dc82019-10-22 14:33:16 -070054 }
55
Gunnar Mills1214b7e2020-06-04 10:11:30 -050056 for (const auto& [path, interfaces] : statuses)
James Feistb49ac872019-05-21 15:12:01 -070057 {
58 bool isChild = false;
Karol Wojciechowski42cbb512021-07-28 17:12:20 +020059 bool isSelf = false;
60 if (selfPath)
61 {
62 if (boost::equals(path.str, *selfPath) ||
63 boost::starts_with(path.str, *selfPath + "/"))
64 {
65 isSelf = true;
66 }
67 }
James Feistb49ac872019-05-21 15:12:01 -070068
69 // managers inventory is all the inventory, don't skip any
James Feist35e257a2020-06-05 13:30:51 -070070 if (!isManagersHealth && !isSelf)
James Feistb49ac872019-05-21 15:12:01 -070071 {
72
73 // We only want to look at this association if either the path
74 // of this association is an inventory item, or one of the
75 // endpoints in this association is a child
76
Gunnar Mills1214b7e2020-06-04 10:11:30 -050077 for (const std::string& child : inventory)
James Feistb49ac872019-05-21 15:12:01 -070078 {
79 if (boost::starts_with(path.str, child))
80 {
81 isChild = true;
82 break;
83 }
84 }
85 if (!isChild)
86 {
87 auto assocIt =
88 interfaces.find("xyz.openbmc_project.Association");
89 if (assocIt == interfaces.end())
90 {
91 continue;
92 }
93 auto endpointsIt = assocIt->second.find("endpoints");
94 if (endpointsIt == assocIt->second.end())
95 {
96 BMCWEB_LOG_ERROR << "Illegal association at "
97 << path.str;
98 continue;
99 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500100 const std::vector<std::string>* endpoints =
James Feistb49ac872019-05-21 15:12:01 -0700101 std::get_if<std::vector<std::string>>(
102 &endpointsIt->second);
103 if (endpoints == nullptr)
104 {
105 BMCWEB_LOG_ERROR << "Illegal association at "
106 << path.str;
107 continue;
108 }
109 bool containsChild = false;
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500110 for (const std::string& endpoint : *endpoints)
James Feistb49ac872019-05-21 15:12:01 -0700111 {
112 if (std::find(inventory.begin(), inventory.end(),
113 endpoint) != inventory.end())
114 {
115 containsChild = true;
116 break;
117 }
118 }
119 if (!containsChild)
120 {
121 continue;
122 }
123 }
124 }
125
126 if (boost::starts_with(path.str, globalInventoryPath) &&
127 boost::ends_with(path.str, "critical"))
128 {
129 health = "Critical";
130 rollup = "Critical";
131 return;
132 }
Ed Tanous3174e4d2020-10-07 11:41:22 -0700133 if (boost::starts_with(path.str, globalInventoryPath) &&
134 boost::ends_with(path.str, "warning"))
James Feistb49ac872019-05-21 15:12:01 -0700135 {
136 health = "Warning";
137 if (rollup != "Critical")
138 {
139 rollup = "Warning";
140 }
141 }
142 else if (boost::ends_with(path.str, "critical"))
143 {
144 rollup = "Critical";
James Feist35e257a2020-06-05 13:30:51 -0700145 if (isSelf)
146 {
147 health = "Critical";
148 return;
149 }
James Feistb49ac872019-05-21 15:12:01 -0700150 }
151 else if (boost::ends_with(path.str, "warning"))
152 {
153 if (rollup != "Critical")
154 {
155 rollup = "Warning";
156 }
James Feist35e257a2020-06-05 13:30:51 -0700157
158 if (isSelf)
159 {
160 health = "Warning";
161 }
James Feistb49ac872019-05-21 15:12:01 -0700162 }
163 }
164 }
165
James Feist5bc2dc82019-10-22 14:33:16 -0700166 // this should only be called once per url, others should get updated by
167 // being added as children to the 'main' health object for the page
James Feistb49ac872019-05-21 15:12:01 -0700168 void populate()
169 {
James Feist9536a142019-11-21 09:02:32 -0800170 if (populated)
171 {
172 return;
173 }
174 populated = true;
James Feistb49ac872019-05-21 15:12:01 -0700175 getAllStatusAssociations();
176 getGlobalPath();
177 }
178
179 void getGlobalPath()
180 {
181 std::shared_ptr<HealthPopulate> self = shared_from_this();
182 crow::connections::systemBus->async_method_call(
183 [self](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500184 std::vector<std::string>& resp) {
James Feistb49ac872019-05-21 15:12:01 -0700185 if (ec || resp.size() != 1)
186 {
187 // no global item, or too many
188 return;
189 }
190 self->globalInventoryPath = std::move(resp[0]);
191 },
192 "xyz.openbmc_project.ObjectMapper",
193 "/xyz/openbmc_project/object_mapper",
Ed Tanous271584a2019-07-09 16:24:22 -0700194 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/", 0,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500195 std::array<const char*, 1>{
James Feistb49ac872019-05-21 15:12:01 -0700196 "xyz.openbmc_project.Inventory.Item.Global"});
197 }
198
199 void getAllStatusAssociations()
200 {
201 std::shared_ptr<HealthPopulate> self = shared_from_this();
202 crow::connections::systemBus->async_method_call(
203 [self](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500204 dbus::utility::ManagedObjectType& resp) {
James Feistb49ac872019-05-21 15:12:01 -0700205 if (ec)
206 {
207 return;
208 }
209 for (auto it = resp.begin(); it != resp.end();)
210 {
211 if (boost::ends_with(it->first.str, "critical") ||
212 boost::ends_with(it->first.str, "warning"))
213 {
214 it++;
215 continue;
216 }
217 it = resp.erase(it);
218 }
219 self->statuses = std::move(resp);
220 },
221 "xyz.openbmc_project.ObjectMapper", "/",
222 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
223 }
224
zhanghch058d1b46d2021-04-01 11:18:24 +0800225 std::shared_ptr<bmcweb::AsyncResp> asyncResp;
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500226 nlohmann::json& jsonStatus;
James Feist5bc2dc82019-10-22 14:33:16 -0700227
228 // we store pointers to other HealthPopulate items so we can update their
229 // members and reduce dbus calls. As we hold a shared_ptr to them, they get
230 // destroyed last, and they need not call populate()
231 std::vector<std::shared_ptr<HealthPopulate>> children;
232
James Feist35e257a2020-06-05 13:30:51 -0700233 // self is used if health is for an individual items status, as this is the
234 // 'lowest most' item, the rollup will equal the health
235 std::optional<std::string> selfPath;
236
James Feistb49ac872019-05-21 15:12:01 -0700237 std::vector<std::string> inventory;
238 bool isManagersHealth = false;
239 dbus::utility::ManagedObjectType statuses;
240 std::string globalInventoryPath = "-"; // default to illegal dbus path
James Feist9536a142019-11-21 09:02:32 -0800241 bool populated = false;
James Feistb49ac872019-05-21 15:12:01 -0700242};
Ed Tanous23a21a12020-07-25 04:45:05 +0000243} // namespace redfish