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 =
61     std::optional<boost::container::flat_map<const char*, probe_type_codes,
62                                              CmpStr>::const_iterator>;
63 FoundProbeTypeT findProbeType(const std::string& probe);
64 
65 struct PerformScan : std::enable_shared_from_this<PerformScan>
66 {
67 
68     PerformScan(nlohmann::json& systemConfiguration,
69                 nlohmann::json& missingConfigurations,
70                 std::list<nlohmann::json>& configurations,
71                 sdbusplus::asio::object_server& objServer,
72                 std::function<void()>&& callback);
73     void updateSystemConfiguration(const nlohmann::json& recordRef,
74                                    const std::string& probeName,
75                                    FoundDevices& foundDevices);
76     void run(void);
77     virtual ~PerformScan();
78     nlohmann::json& _systemConfiguration;
79     nlohmann::json& _missingConfigurations;
80     std::list<nlohmann::json> _configurations;
81     sdbusplus::asio::object_server& objServer;
82     std::function<void()> _callback;
83     bool _passed = false;
84     MapperGetSubTreeResponse dbusProbeObjects;
85     std::vector<std::string> passedProbes;
86 };
87 
88 // this class finds the needed dbus fields and on destruction runs the probe
89 struct PerformProbe : std::enable_shared_from_this<PerformProbe>
90 {
91     PerformProbe(nlohmann::json& recordRef,
92                  const std::vector<std::string>& probeCommand,
93                  std::string probeName, std::shared_ptr<PerformScan>& scanPtr);
94     virtual ~PerformProbe();
95 
96     nlohmann::json& recordRef;
97     std::vector<std::string> _probeCommand;
98     std::string probeName;
99     std::shared_ptr<PerformScan> scan;
100 };
101 
102 inline void logDeviceAdded(const nlohmann::json& record)
103 {
104 
105     if (!deviceHasLogging(record))
106     {
107         return;
108     }
109     auto findType = record.find("Type");
110     auto findAsset =
111         record.find("xyz.openbmc_project.Inventory.Decorator.Asset");
112 
113     std::string model = "Unknown";
114     std::string type = "Unknown";
115     std::string sn = "Unknown";
116     std::string name = "Unknown";
117 
118     if (findType != record.end())
119     {
120         type = findType->get<std::string>();
121     }
122     if (findAsset != record.end())
123     {
124         auto findModel = findAsset->find("Model");
125         auto findSn = findAsset->find("SerialNumber");
126         if (findModel != findAsset->end())
127         {
128             model = findModel->get<std::string>();
129         }
130         if (findSn != findAsset->end())
131         {
132             const std::string* getSn = findSn->get_ptr<const std::string*>();
133             if (getSn != nullptr)
134             {
135                 sn = *getSn;
136             }
137             else
138             {
139                 sn = findSn->dump();
140             }
141         }
142     }
143 
144     auto findName = record.find("Name");
145     if (findName != record.end())
146     {
147         name = findName->get<std::string>();
148     }
149 
150     sd_journal_send("MESSAGE=Inventory Added: %s", name.c_str(), "PRIORITY=%i",
151                     LOG_INFO, "REDFISH_MESSAGE_ID=%s",
152                     "OpenBMC.0.1.InventoryAdded",
153                     "REDFISH_MESSAGE_ARGS=%s,%s,%s", model.c_str(),
154                     type.c_str(), sn.c_str(), "NAME=%s", name.c_str(), NULL);
155 }
156 
157 inline void logDeviceRemoved(const nlohmann::json& record)
158 {
159     if (!deviceHasLogging(record))
160     {
161         return;
162     }
163     auto findType = record.find("Type");
164     auto findAsset =
165         record.find("xyz.openbmc_project.Inventory.Decorator.Asset");
166 
167     std::string model = "Unknown";
168     std::string type = "Unknown";
169     std::string sn = "Unknown";
170     std::string name = "Unknown";
171 
172     if (findType != record.end())
173     {
174         type = findType->get<std::string>();
175     }
176     if (findAsset != record.end())
177     {
178         auto findModel = findAsset->find("Model");
179         auto findSn = findAsset->find("SerialNumber");
180         if (findModel != findAsset->end())
181         {
182             model = findModel->get<std::string>();
183         }
184         if (findSn != findAsset->end())
185         {
186             const std::string* getSn = findSn->get_ptr<const std::string*>();
187             if (getSn != nullptr)
188             {
189                 sn = *getSn;
190             }
191             else
192             {
193                 sn = findSn->dump();
194             }
195         }
196     }
197 
198     auto findName = record.find("Name");
199     if (findName != record.end())
200     {
201         name = findName->get<std::string>();
202     }
203 
204     sd_journal_send("MESSAGE=Inventory Removed: %s", name.c_str(),
205                     "PRIORITY=%i", LOG_INFO, "REDFISH_MESSAGE_ID=%s",
206                     "OpenBMC.0.1.InventoryRemoved",
207                     "REDFISH_MESSAGE_ARGS=%s,%s,%s", model.c_str(),
208                     type.c_str(), sn.c_str(), "NAME=%s", name.c_str(), NULL);
209 }
210