blob: fe65ebfbcb400fb4224c74d78a63196f740fe55a [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>
23#include <variant>
24
25namespace redfish
26{
27
28struct HealthPopulate : std::enable_shared_from_this<HealthPopulate>
29{
30 HealthPopulate(const std::shared_ptr<AsyncResp> &asyncResp) :
James Feist5bc2dc82019-10-22 14:33:16 -070031 asyncResp(asyncResp), jsonStatus(asyncResp->res.jsonValue["Status"])
32 {
33 }
34
35 HealthPopulate(const std::shared_ptr<AsyncResp> &asyncResp,
36 nlohmann::json &status) :
37 asyncResp(asyncResp),
38 jsonStatus(status)
James Feistb49ac872019-05-21 15:12:01 -070039 {
40 }
41
42 ~HealthPopulate()
43 {
James Feist5bc2dc82019-10-22 14:33:16 -070044 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
James Feist5bc2dc82019-10-22 14:33:16 -070050 for (const std::shared_ptr<HealthPopulate> &health : children)
51 {
52 health->globalInventoryPath = globalInventoryPath;
53 health->statuses = statuses;
54 }
55
James Feistb49ac872019-05-21 15:12:01 -070056 for (const auto &[path, interfaces] : statuses)
57 {
58 bool isChild = false;
59
60 // managers inventory is all the inventory, don't skip any
61 if (!isManagersHealth)
62 {
63
64 // We only want to look at this association if either the path
65 // of this association is an inventory item, or one of the
66 // endpoints in this association is a child
67
68 for (const std::string &child : inventory)
69 {
70 if (boost::starts_with(path.str, child))
71 {
72 isChild = true;
73 break;
74 }
75 }
76 if (!isChild)
77 {
78 auto assocIt =
79 interfaces.find("xyz.openbmc_project.Association");
80 if (assocIt == interfaces.end())
81 {
82 continue;
83 }
84 auto endpointsIt = assocIt->second.find("endpoints");
85 if (endpointsIt == assocIt->second.end())
86 {
87 BMCWEB_LOG_ERROR << "Illegal association at "
88 << path.str;
89 continue;
90 }
91 const std::vector<std::string> *endpoints =
92 std::get_if<std::vector<std::string>>(
93 &endpointsIt->second);
94 if (endpoints == nullptr)
95 {
96 BMCWEB_LOG_ERROR << "Illegal association at "
97 << path.str;
98 continue;
99 }
100 bool containsChild = false;
101 for (const std::string &endpoint : *endpoints)
102 {
103 if (std::find(inventory.begin(), inventory.end(),
104 endpoint) != inventory.end())
105 {
106 containsChild = true;
107 break;
108 }
109 }
110 if (!containsChild)
111 {
112 continue;
113 }
114 }
115 }
116
117 if (boost::starts_with(path.str, globalInventoryPath) &&
118 boost::ends_with(path.str, "critical"))
119 {
120 health = "Critical";
121 rollup = "Critical";
122 return;
123 }
124 else if (boost::starts_with(path.str, globalInventoryPath) &&
125 boost::ends_with(path.str, "warning"))
126 {
127 health = "Warning";
128 if (rollup != "Critical")
129 {
130 rollup = "Warning";
131 }
132 }
133 else if (boost::ends_with(path.str, "critical"))
134 {
135 rollup = "Critical";
136 }
137 else if (boost::ends_with(path.str, "warning"))
138 {
139 if (rollup != "Critical")
140 {
141 rollup = "Warning";
142 }
143 }
144 }
145 }
146
James Feist5bc2dc82019-10-22 14:33:16 -0700147 // this should only be called once per url, others should get updated by
148 // being added as children to the 'main' health object for the page
James Feistb49ac872019-05-21 15:12:01 -0700149 void populate()
150 {
James Feist9536a142019-11-21 09:02:32 -0800151 if (populated)
152 {
153 return;
154 }
155 populated = true;
James Feistb49ac872019-05-21 15:12:01 -0700156 getAllStatusAssociations();
157 getGlobalPath();
158 }
159
160 void getGlobalPath()
161 {
162 std::shared_ptr<HealthPopulate> self = shared_from_this();
163 crow::connections::systemBus->async_method_call(
164 [self](const boost::system::error_code ec,
165 std::vector<std::string> &resp) {
166 if (ec || resp.size() != 1)
167 {
168 // no global item, or too many
169 return;
170 }
171 self->globalInventoryPath = std::move(resp[0]);
172 },
173 "xyz.openbmc_project.ObjectMapper",
174 "/xyz/openbmc_project/object_mapper",
Ed Tanous271584a2019-07-09 16:24:22 -0700175 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/", 0,
James Feistb49ac872019-05-21 15:12:01 -0700176 std::array<const char *, 1>{
177 "xyz.openbmc_project.Inventory.Item.Global"});
178 }
179
180 void getAllStatusAssociations()
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,
185 dbus::utility::ManagedObjectType &resp) {
186 if (ec)
187 {
188 return;
189 }
190 for (auto it = resp.begin(); it != resp.end();)
191 {
192 if (boost::ends_with(it->first.str, "critical") ||
193 boost::ends_with(it->first.str, "warning"))
194 {
195 it++;
196 continue;
197 }
198 it = resp.erase(it);
199 }
200 self->statuses = std::move(resp);
201 },
202 "xyz.openbmc_project.ObjectMapper", "/",
203 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
204 }
205
206 std::shared_ptr<AsyncResp> asyncResp;
James Feist5bc2dc82019-10-22 14:33:16 -0700207 nlohmann::json &jsonStatus;
208
209 // we store pointers to other HealthPopulate items so we can update their
210 // members and reduce dbus calls. As we hold a shared_ptr to them, they get
211 // destroyed last, and they need not call populate()
212 std::vector<std::shared_ptr<HealthPopulate>> children;
213
James Feistb49ac872019-05-21 15:12:01 -0700214 std::vector<std::string> inventory;
215 bool isManagersHealth = false;
216 dbus::utility::ManagedObjectType statuses;
217 std::string globalInventoryPath = "-"; // default to illegal dbus path
James Feist9536a142019-11-21 09:02:32 -0800218 bool populated = false;
James Feistb49ac872019-05-21 15:12:01 -0700219};
220} // namespace redfish