blob: da4f2d9fe7dd9cdd1b6a0aa9e16a4f09d5aa9f61 [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) :
31 asyncResp(asyncResp)
32 {
33 }
34
35 ~HealthPopulate()
36 {
37 nlohmann::json &health = asyncResp->res.jsonValue["Status"]["Health"];
38 nlohmann::json &rollup =
39 asyncResp->res.jsonValue["Status"]["HealthRollup"];
40
41 health = "OK";
42 rollup = "OK";
43
44 for (const auto &[path, interfaces] : statuses)
45 {
46 bool isChild = false;
47
48 // managers inventory is all the inventory, don't skip any
49 if (!isManagersHealth)
50 {
51
52 // We only want to look at this association if either the path
53 // of this association is an inventory item, or one of the
54 // endpoints in this association is a child
55
56 for (const std::string &child : inventory)
57 {
58 if (boost::starts_with(path.str, child))
59 {
60 isChild = true;
61 break;
62 }
63 }
64 if (!isChild)
65 {
66 auto assocIt =
67 interfaces.find("xyz.openbmc_project.Association");
68 if (assocIt == interfaces.end())
69 {
70 continue;
71 }
72 auto endpointsIt = assocIt->second.find("endpoints");
73 if (endpointsIt == assocIt->second.end())
74 {
75 BMCWEB_LOG_ERROR << "Illegal association at "
76 << path.str;
77 continue;
78 }
79 const std::vector<std::string> *endpoints =
80 std::get_if<std::vector<std::string>>(
81 &endpointsIt->second);
82 if (endpoints == nullptr)
83 {
84 BMCWEB_LOG_ERROR << "Illegal association at "
85 << path.str;
86 continue;
87 }
88 bool containsChild = false;
89 for (const std::string &endpoint : *endpoints)
90 {
91 if (std::find(inventory.begin(), inventory.end(),
92 endpoint) != inventory.end())
93 {
94 containsChild = true;
95 break;
96 }
97 }
98 if (!containsChild)
99 {
100 continue;
101 }
102 }
103 }
104
105 if (boost::starts_with(path.str, globalInventoryPath) &&
106 boost::ends_with(path.str, "critical"))
107 {
108 health = "Critical";
109 rollup = "Critical";
110 return;
111 }
112 else if (boost::starts_with(path.str, globalInventoryPath) &&
113 boost::ends_with(path.str, "warning"))
114 {
115 health = "Warning";
116 if (rollup != "Critical")
117 {
118 rollup = "Warning";
119 }
120 }
121 else if (boost::ends_with(path.str, "critical"))
122 {
123 rollup = "Critical";
124 }
125 else if (boost::ends_with(path.str, "warning"))
126 {
127 if (rollup != "Critical")
128 {
129 rollup = "Warning";
130 }
131 }
132 }
133 }
134
135 void populate()
136 {
137 getAllStatusAssociations();
138 getGlobalPath();
139 }
140
141 void getGlobalPath()
142 {
143 std::shared_ptr<HealthPopulate> self = shared_from_this();
144 crow::connections::systemBus->async_method_call(
145 [self](const boost::system::error_code ec,
146 std::vector<std::string> &resp) {
147 if (ec || resp.size() != 1)
148 {
149 // no global item, or too many
150 return;
151 }
152 self->globalInventoryPath = std::move(resp[0]);
153 },
154 "xyz.openbmc_project.ObjectMapper",
155 "/xyz/openbmc_project/object_mapper",
156 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/",
157 int32_t(0),
158 std::array<const char *, 1>{
159 "xyz.openbmc_project.Inventory.Item.Global"});
160 }
161
162 void getAllStatusAssociations()
163 {
164 std::shared_ptr<HealthPopulate> self = shared_from_this();
165 crow::connections::systemBus->async_method_call(
166 [self](const boost::system::error_code ec,
167 dbus::utility::ManagedObjectType &resp) {
168 if (ec)
169 {
170 return;
171 }
172 for (auto it = resp.begin(); it != resp.end();)
173 {
174 if (boost::ends_with(it->first.str, "critical") ||
175 boost::ends_with(it->first.str, "warning"))
176 {
177 it++;
178 continue;
179 }
180 it = resp.erase(it);
181 }
182 self->statuses = std::move(resp);
183 },
184 "xyz.openbmc_project.ObjectMapper", "/",
185 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
186 }
187
188 std::shared_ptr<AsyncResp> asyncResp;
189 std::vector<std::string> inventory;
190 bool isManagersHealth = false;
191 dbus::utility::ManagedObjectType statuses;
192 std::string globalInventoryPath = "-"; // default to illegal dbus path
193};
194} // namespace redfish