1 /*
2 // Copyright (c) 2018 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 /// \file entity_manager.hpp
17 
18 #pragma once
19 
20 #include "utils.hpp"
21 
22 #include <systemd/sd-journal.h>
23 
24 #include <boost/container/flat_map.hpp>
25 #include <nlohmann/json.hpp>
26 #include <sdbusplus/asio/object_server.hpp>
27 
28 #include <iostream>
29 #include <list>
30 #include <optional>
31 #include <string>
32 
33 struct DBusDeviceDescriptor
34 {
35     DBusInterface interface;
36     std::string path;
37 };
38 
39 using FoundDevices = std::vector<DBusDeviceDescriptor>;
40 
41 struct CmpStr
42 {
43     bool operator()(const char* a, const char* b) const
44     {
45         return std::strcmp(a, b) < 0;
46     }
47 };
48 
49 // underscore T for collison with dbus c api
50 enum class probe_type_codes
51 {
52     FALSE_T,
53     TRUE_T,
54     AND,
55     OR,
56     FOUND,
57     MATCH_ONE
58 };
59 
60 using FoundProbeTypeT = std::optional<boost::container::flat_map<
61     const char*, probe_type_codes, CmpStr>::const_iterator>;
62 FoundProbeTypeT findProbeType(const std::string& probe);
63 
64 struct PerformScan : std::enable_shared_from_this<PerformScan>
65 {
66     PerformScan(nlohmann::json& systemConfiguration,
67                 nlohmann::json& missingConfigurations,
68                 std::list<nlohmann::json>& configurations,
69                 sdbusplus::asio::object_server& objServer,
70                 std::function<void()>&& callback);
71     void updateSystemConfiguration(const nlohmann::json& recordRef,
72                                    const std::string& probeName,
73                                    FoundDevices& foundDevices);
74     void run();
75     virtual ~PerformScan();
76     nlohmann::json& _systemConfiguration;
77     nlohmann::json& _missingConfigurations;
78     std::list<nlohmann::json> _configurations;
79     sdbusplus::asio::object_server& objServer;
80     std::function<void()> _callback;
81     bool _passed = false;
82     MapperGetSubTreeResponse dbusProbeObjects;
83     std::vector<std::string> passedProbes;
84 };
85 
86 // this class finds the needed dbus fields and on destruction runs the probe
87 struct PerformProbe : std::enable_shared_from_this<PerformProbe>
88 {
89     PerformProbe(nlohmann::json& recordRef,
90                  const std::vector<std::string>& probeCommand,
91                  std::string probeName, std::shared_ptr<PerformScan>& scanPtr);
92     virtual ~PerformProbe();
93 
94     nlohmann::json& recordRef;
95     std::vector<std::string> _probeCommand;
96     std::string probeName;
97     std::shared_ptr<PerformScan> scan;
98 };
99 
100 inline void logDeviceAdded(const nlohmann::json& record)
101 {
102     if (!deviceHasLogging(record))
103     {
104         return;
105     }
106     auto findType = record.find("Type");
107     auto findAsset =
108         record.find("xyz.openbmc_project.Inventory.Decorator.Asset");
109 
110     std::string model = "Unknown";
111     std::string type = "Unknown";
112     std::string sn = "Unknown";
113     std::string name = "Unknown";
114 
115     if (findType != record.end())
116     {
117         type = findType->get<std::string>();
118     }
119     if (findAsset != record.end())
120     {
121         auto findModel = findAsset->find("Model");
122         auto findSn = findAsset->find("SerialNumber");
123         if (findModel != findAsset->end())
124         {
125             model = findModel->get<std::string>();
126         }
127         if (findSn != findAsset->end())
128         {
129             const std::string* getSn = findSn->get_ptr<const std::string*>();
130             if (getSn != nullptr)
131             {
132                 sn = *getSn;
133             }
134             else
135             {
136                 sn = findSn->dump();
137             }
138         }
139     }
140 
141     auto findName = record.find("Name");
142     if (findName != record.end())
143     {
144         name = findName->get<std::string>();
145     }
146 
147     sd_journal_send("MESSAGE=Inventory Added: %s", name.c_str(), "PRIORITY=%i",
148                     LOG_INFO, "REDFISH_MESSAGE_ID=%s",
149                     "OpenBMC.0.1.InventoryAdded",
150                     "REDFISH_MESSAGE_ARGS=%s,%s,%s", model.c_str(),
151                     type.c_str(), sn.c_str(), "NAME=%s", name.c_str(), NULL);
152 }
153 
154 inline void logDeviceRemoved(const nlohmann::json& record)
155 {
156     if (!deviceHasLogging(record))
157     {
158         return;
159     }
160     auto findType = record.find("Type");
161     auto findAsset =
162         record.find("xyz.openbmc_project.Inventory.Decorator.Asset");
163 
164     std::string model = "Unknown";
165     std::string type = "Unknown";
166     std::string sn = "Unknown";
167     std::string name = "Unknown";
168 
169     if (findType != record.end())
170     {
171         type = findType->get<std::string>();
172     }
173     if (findAsset != record.end())
174     {
175         auto findModel = findAsset->find("Model");
176         auto findSn = findAsset->find("SerialNumber");
177         if (findModel != findAsset->end())
178         {
179             model = findModel->get<std::string>();
180         }
181         if (findSn != findAsset->end())
182         {
183             const std::string* getSn = findSn->get_ptr<const std::string*>();
184             if (getSn != nullptr)
185             {
186                 sn = *getSn;
187             }
188             else
189             {
190                 sn = findSn->dump();
191             }
192         }
193     }
194 
195     auto findName = record.find("Name");
196     if (findName != record.end())
197     {
198         name = findName->get<std::string>();
199     }
200 
201     sd_journal_send("MESSAGE=Inventory Removed: %s", name.c_str(),
202                     "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
203                     "OpenBMC.0.1.InventoryRemoved",
204                     "REDFISH_MESSAGE_ARGS=%s,%s,%s", model.c_str(),
205                     type.c_str(), sn.c_str(), "NAME=%s", name.c_str(), NULL);
206 }
207