1 /**
2  * Copyright © 2021 IBM 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 #include "get_managed_objects.hpp"
17 
18 #include "../manager.hpp"
19 #include "event.hpp"
20 
21 namespace phosphor::fan::control::json
22 {
23 
24 using json = nlohmann::json;
25 
26 GetManagedObjects::GetManagedObjects(const json& jsonObj,
27                                      const std::vector<Group>& groups) :
28     ActionBase(jsonObj, groups)
29 {
30     setActions(jsonObj);
31 }
32 
33 void GetManagedObjects::run(Zone& zone)
34 {
35     std::set<std::string> services;
36 
37     // Call Manager::addObjects to refresh the values of the group members.
38     // If there is an ObjectManager interface that handles them, then
39     // the code can combine all members in the same service down to one call.
40     // If no ObjectManager, then still need addObjects calls for each.
41     for (const auto& group : _groups)
42     {
43         for (const auto& member : group.getMembers())
44         {
45             try
46             {
47                 std::vector<std::string> objMgrPaths;
48 
49                 const auto& service =
50                     zone.getManager()->getService(member, group.getInterface());
51 
52                 if (!service.empty())
53                 {
54                     objMgrPaths = zone.getManager()->getPaths(
55                         service, "org.freedesktop.DBus.ObjectManager");
56                 }
57                 else
58                 {
59                     continue;
60                 }
61 
62                 // Look for the ObjectManager as an ancestor of the path.
63                 auto hasObjMgr = std::any_of(objMgrPaths.begin(),
64                                              objMgrPaths.end(),
65                                              [member](const auto& path) {
66                     return member.find(path) != std::string::npos;
67                 });
68 
69                 if (!hasObjMgr || services.find(service) == services.end())
70                 {
71                     if (hasObjMgr)
72                     {
73                         services.insert(service);
74                     }
75 
76                     zone.getManager()->addObjects(member, group.getInterface(),
77                                                   group.getProperty());
78                 }
79             }
80             catch (const std::exception& e)
81             {
82                 // May have been called from a name_owner_changed trigger
83                 // and the service may have been lost.
84             }
85         }
86     }
87 
88     // Perform the actions
89     std::for_each(_actions.begin(), _actions.end(),
90                   [](auto& action) { action->run(); });
91 }
92 
93 void GetManagedObjects::setZones(
94     std::vector<std::reference_wrapper<Zone>>& zones)
95 {
96     for (auto& zone : zones)
97     {
98         this->addZone(zone);
99         // Add zone to _actions
100         std::for_each(_actions.begin(), _actions.end(),
101                       [&zone](std::unique_ptr<ActionBase>& action) {
102             action->addZone(zone);
103         });
104     }
105 }
106 
107 void GetManagedObjects::setActions(const json& jsonObj)
108 {
109     if (!jsonObj.contains("actions"))
110     {
111         return;
112     }
113 
114     for (const auto& jsonAct : jsonObj["actions"])
115     {
116         if (!jsonAct.contains("name"))
117         {
118             throw ActionParseError{getName(), "Missing required action name"};
119         }
120 
121         // Get any configured profile restrictions on the action
122         std::vector<std::string> profiles;
123         if (jsonAct.contains("profiles"))
124         {
125             profiles = jsonAct["profiles"].get<std::vector<std::string>>();
126         }
127 
128         // Set the groups configured for each action run when the timer expires
129         std::vector<Group> groups;
130         Event::setGroups(jsonAct, profiles, groups);
131 
132         // If no groups on that action, use our own groups instead
133         const std::vector<Group>* groupPtr = &groups;
134         if (groups.empty())
135         {
136             groupPtr = &_groups;
137         }
138 
139         // List of zones is set on these actions by overriden setZones()
140         auto actObj = ActionFactory::getAction(
141             jsonAct["name"].get<std::string>(), jsonAct, *groupPtr, {});
142         if (actObj)
143         {
144             _actions.emplace_back(std::move(actObj));
145         }
146     }
147 }
148 
149 } // namespace phosphor::fan::control::json
150