blob: 930eaee38f344b01670757b0fe0bc908232a567f [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",
Ed Tanous271584a2019-07-09 16:24:22 -0700156 "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", "/", 0,
James Feistb49ac872019-05-21 15:12:01 -0700157 std::array<const char *, 1>{
158 "xyz.openbmc_project.Inventory.Item.Global"});
159 }
160
161 void getAllStatusAssociations()
162 {
163 std::shared_ptr<HealthPopulate> self = shared_from_this();
164 crow::connections::systemBus->async_method_call(
165 [self](const boost::system::error_code ec,
166 dbus::utility::ManagedObjectType &resp) {
167 if (ec)
168 {
169 return;
170 }
171 for (auto it = resp.begin(); it != resp.end();)
172 {
173 if (boost::ends_with(it->first.str, "critical") ||
174 boost::ends_with(it->first.str, "warning"))
175 {
176 it++;
177 continue;
178 }
179 it = resp.erase(it);
180 }
181 self->statuses = std::move(resp);
182 },
183 "xyz.openbmc_project.ObjectMapper", "/",
184 "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
185 }
186
187 std::shared_ptr<AsyncResp> asyncResp;
188 std::vector<std::string> inventory;
189 bool isManagersHealth = false;
190 dbus::utility::ManagedObjectType statuses;
191 std::string globalInventoryPath = "-"; // default to illegal dbus path
192};
193} // namespace redfish