blob: 4f21b3e438c7bff8efd92aae3e7aba14423b6ba5 [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
20#include <boost/algorithm/string/predicate.hpp>
21#include <boost/container/flat_set.hpp>
22#include <dbus_singleton.hpp>
Gunnar Mills1214b7e2020-06-04 10:11:30 -050023
James Feistb49ac872019-05-21 15:12:01 -070024#include <variant>
25
26namespace redfish
27{
28
29struct HealthPopulate : std::enable_shared_from_this<HealthPopulate>
30{
Ed Tanous23a21a12020-07-25 04:45:05 +000031 HealthPopulate(const std::shared_ptr<AsyncResp>& asyncRespIn) :
32 asyncResp(asyncRespIn), jsonStatus(asyncResp->res.jsonValue["Status"])
Gunnar Mills1214b7e2020-06-04 10:11:30 -050033 {}
James Feist5bc2dc82019-10-22 14:33:16 -070034
Ed Tanous23a21a12020-07-25 04:45:05 +000035 HealthPopulate(const std::shared_ptr<AsyncResp>& asyncRespIn,
Gunnar Mills1214b7e2020-06-04 10:11:30 -050036 nlohmann::json& status) :
Ed Tanous23a21a12020-07-25 04:45:05 +000037 asyncResp(asyncRespIn),
James Feist5bc2dc82019-10-22 14:33:16 -070038 jsonStatus(status)
Gunnar Mills1214b7e2020-06-04 10:11:30 -050039 {}
James Feistb49ac872019-05-21 15:12:01 -070040
41 ~HealthPopulate()
42 {
Gunnar Mills1214b7e2020-06-04 10:11:30 -050043 nlohmann::json& health = jsonStatus["Health"];
44 nlohmann::json& rollup = jsonStatus["HealthRollup"];
James Feistb49ac872019-05-21 15:12:01 -070045
46 health = "OK";
47 rollup = "OK";
48
Ed Tanous23a21a12020-07-25 04:45:05 +000049 for (const std::shared_ptr<HealthPopulate>& healthChild : children)
James Feist5bc2dc82019-10-22 14:33:16 -070050 {
Ed Tanous23a21a12020-07-25 04:45:05 +000051 healthChild->globalInventoryPath = globalInventoryPath;
52 healthChild->statuses = statuses;
James Feist5bc2dc82019-10-22 14:33:16 -070053 }
54
Gunnar Mills1214b7e2020-06-04 10:11:30 -050055 for (const auto& [path, interfaces] : statuses)
James Feistb49ac872019-05-21 15:12:01 -070056 {
57 bool isChild = false;
James Feist35e257a2020-06-05 13:30:51 -070058 bool isSelf =
59 selfPath ? boost::starts_with(path.str, *selfPath) : false;
James Feistb49ac872019-05-21 15:12:01 -070060
61 // managers inventory is all the inventory, don't skip any
James Feist35e257a2020-06-05 13:30:51 -070062 if (!isManagersHealth && !isSelf)
James Feistb49ac872019-05-21 15:12:01 -070063 {
64
65 // We only want to look at this association if either the path
66 // of this association is an inventory item, or one of the
67 // endpoints in this association is a child
68
Gunnar Mills1214b7e2020-06-04 10:11:30 -050069 for (const std::string& child : inventory)
James Feistb49ac872019-05-21 15:12:01 -070070 {
71 if (boost::starts_with(path.str, child))
72 {
73 isChild = true;
74 break;
75 }
76 }
77 if (!isChild)
78 {
79 auto assocIt =
80 interfaces.find("xyz.openbmc_project.Association");
81 if (assocIt == interfaces.end())
82 {
83 continue;
84 }
85 auto endpointsIt = assocIt->second.find("endpoints");
86 if (endpointsIt == assocIt->second.end())
87 {
88 BMCWEB_LOG_ERROR << "Illegal association at "
89 << path.str;
90 continue;
91 }
Gunnar Mills1214b7e2020-06-04 10:11:30 -050092 const std::vector<std::string>* endpoints =
James Feistb49ac872019-05-21 15:12:01 -070093 std::get_if<std::vector<std::string>>(
94 &endpointsIt->second);
95 if (endpoints == nullptr)
96 {
97 BMCWEB_LOG_ERROR << "Illegal association at "
98 << path.str;
99 continue;
100 }
101 bool containsChild = false;
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500102 for (const std::string& endpoint : *endpoints)
James Feistb49ac872019-05-21 15:12:01 -0700103 {
104 if (std::find(inventory.begin(), inventory.end(),
105 endpoint) != inventory.end())
106 {
107 containsChild = true;
108 break;
109 }
110 }
111 if (!containsChild)
112 {
113 continue;
114 }
115 }
116 }
117
118 if (boost::starts_with(path.str, globalInventoryPath) &&
119 boost::ends_with(path.str, "critical"))
120 {
121 health = "Critical";
122 rollup = "Critical";
123 return;
124 }
125 else if (boost::starts_with(path.str, globalInventoryPath) &&
126 boost::ends_with(path.str, "warning"))
127 {
128 health = "Warning";
129 if (rollup != "Critical")
130 {
131 rollup = "Warning";
132 }
133 }
134 else if (boost::ends_with(path.str, "critical"))
135 {
136 rollup = "Critical";
James Feist35e257a2020-06-05 13:30:51 -0700137 if (isSelf)
138 {
139 health = "Critical";
140 return;
141 }
James Feistb49ac872019-05-21 15:12:01 -0700142 }
143 else if (boost::ends_with(path.str, "warning"))
144 {
145 if (rollup != "Critical")
146 {
147 rollup = "Warning";
148 }
James Feist35e257a2020-06-05 13:30:51 -0700149
150 if (isSelf)
151 {
152 health = "Warning";
153 }
James Feistb49ac872019-05-21 15:12:01 -0700154 }
155 }
156 }
157
James Feist5bc2dc82019-10-22 14:33:16 -0700158 // this should only be called once per url, others should get updated by
159 // being added as children to the 'main' health object for the page
James Feistb49ac872019-05-21 15:12:01 -0700160 void populate()
161 {
James Feist9536a142019-11-21 09:02:32 -0800162 if (populated)
163 {
164 return;
165 }
166 populated = true;
James Feistb49ac872019-05-21 15:12:01 -0700167 getAllStatusAssociations();
168 getGlobalPath();
169 }
170
171 void getGlobalPath()
172 {
173 std::shared_ptr<HealthPopulate> self = shared_from_this();
174 crow::connections::systemBus->async_method_call(
175 [self](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500176 std::vector<std::string>& resp) {
James Feistb49ac872019-05-21 15:12:01 -0700177 if (ec || resp.size() != 1)
178 {
179 // no global item, or too many
180 return;
181 }
182 self->globalInventoryPath = std::move(resp[0]);
183 },
184 "xyz.openbmc_project.ObjectMapper",
185 "/xyz/openbmc_project/object_mapper",
Ed Tanous271584a2019-07-09 16:24:22 -0700186 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/", 0,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500187 std::array<const char*, 1>{
James Feistb49ac872019-05-21 15:12:01 -0700188 "xyz.openbmc_project.Inventory.Item.Global"});
189 }
190
191 void getAllStatusAssociations()
192 {
193 std::shared_ptr<HealthPopulate> self = shared_from_this();
194 crow::connections::systemBus->async_method_call(
195 [self](const boost::system::error_code ec,
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500196 dbus::utility::ManagedObjectType& resp) {
James Feistb49ac872019-05-21 15:12:01 -0700197 if (ec)
198 {
199 return;
200 }
201 for (auto it = resp.begin(); it != resp.end();)
202 {
203 if (boost::ends_with(it->first.str, "critical") ||
204 boost::ends_with(it->first.str, "warning"))
205 {
206 it++;
207 continue;
208 }
209 it = resp.erase(it);
210 }
211 self->statuses = std::move(resp);
212 },
213 "xyz.openbmc_project.ObjectMapper", "/",
214 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
215 }
216
217 std::shared_ptr<AsyncResp> asyncResp;
Gunnar Mills1214b7e2020-06-04 10:11:30 -0500218 nlohmann::json& jsonStatus;
James Feist5bc2dc82019-10-22 14:33:16 -0700219
220 // we store pointers to other HealthPopulate items so we can update their
221 // members and reduce dbus calls. As we hold a shared_ptr to them, they get
222 // destroyed last, and they need not call populate()
223 std::vector<std::shared_ptr<HealthPopulate>> children;
224
James Feist35e257a2020-06-05 13:30:51 -0700225 // self is used if health is for an individual items status, as this is the
226 // 'lowest most' item, the rollup will equal the health
227 std::optional<std::string> selfPath;
228
James Feistb49ac872019-05-21 15:12:01 -0700229 std::vector<std::string> inventory;
230 bool isManagersHealth = false;
231 dbus::utility::ManagedObjectType statuses;
232 std::string globalInventoryPath = "-"; // default to illegal dbus path
James Feist9536a142019-11-21 09:02:32 -0800233 bool populated = false;
James Feistb49ac872019-05-21 15:12:01 -0700234};
Ed Tanous23a21a12020-07-25 04:45:05 +0000235} // namespace redfish